github.com/EngineerKamesh/gofullstack@v0.0.0-20180609171605-d41341d7d4ee/volume3/section2/3dgopher/static/js/three.js (about)

     1  (function (global, factory) {
     2  	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
     3  	typeof define === 'function' && define.amd ? define(['exports'], factory) :
     4  	(factory((global.THREE = global.THREE || {})));
     5  }(this, (function (exports) { 'use strict';
     6  
     7  	// Polyfills
     8  
     9  	if ( Number.EPSILON === undefined ) {
    10  
    11  		Number.EPSILON = Math.pow( 2, - 52 );
    12  
    13  	}
    14  
    15  	//
    16  
    17  	if ( Math.sign === undefined ) {
    18  
    19  		// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
    20  
    21  		Math.sign = function ( x ) {
    22  
    23  			return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x;
    24  
    25  		};
    26  
    27  	}
    28  
    29  	if ( Function.prototype.name === undefined ) {
    30  
    31  		// Missing in IE9-11.
    32  		// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
    33  
    34  		Object.defineProperty( Function.prototype, 'name', {
    35  
    36  			get: function () {
    37  
    38  				return this.toString().match( /^\s*function\s*([^\(\s]*)/ )[ 1 ];
    39  
    40  			}
    41  
    42  		} );
    43  
    44  	}
    45  
    46  	if ( Object.assign === undefined ) {
    47  
    48  		// Missing in IE.
    49  		// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
    50  
    51  		( function () {
    52  
    53  			Object.assign = function ( target ) {
    54  
    55  				'use strict';
    56  
    57  				if ( target === undefined || target === null ) {
    58  
    59  					throw new TypeError( 'Cannot convert undefined or null to object' );
    60  
    61  				}
    62  
    63  				var output = Object( target );
    64  
    65  				for ( var index = 1; index < arguments.length; index ++ ) {
    66  
    67  					var source = arguments[ index ];
    68  
    69  					if ( source !== undefined && source !== null ) {
    70  
    71  						for ( var nextKey in source ) {
    72  
    73  							if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) {
    74  
    75  								output[ nextKey ] = source[ nextKey ];
    76  
    77  							}
    78  
    79  						}
    80  
    81  					}
    82  
    83  				}
    84  
    85  				return output;
    86  
    87  			};
    88  
    89  		} )();
    90  
    91  	}
    92  
    93  	/**
    94  	 * https://github.com/mrdoob/eventdispatcher.js/
    95  	 */
    96  
    97  	function EventDispatcher() {}
    98  
    99  	EventDispatcher.prototype = {
   100  
   101  		addEventListener: function ( type, listener ) {
   102  
   103  			if ( this._listeners === undefined ) this._listeners = {};
   104  
   105  			var listeners = this._listeners;
   106  
   107  			if ( listeners[ type ] === undefined ) {
   108  
   109  				listeners[ type ] = [];
   110  
   111  			}
   112  
   113  			if ( listeners[ type ].indexOf( listener ) === - 1 ) {
   114  
   115  				listeners[ type ].push( listener );
   116  
   117  			}
   118  
   119  		},
   120  
   121  		hasEventListener: function ( type, listener ) {
   122  
   123  			if ( this._listeners === undefined ) return false;
   124  
   125  			var listeners = this._listeners;
   126  
   127  			return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;
   128  
   129  		},
   130  
   131  		removeEventListener: function ( type, listener ) {
   132  
   133  			if ( this._listeners === undefined ) return;
   134  
   135  			var listeners = this._listeners;
   136  			var listenerArray = listeners[ type ];
   137  
   138  			if ( listenerArray !== undefined ) {
   139  
   140  				var index = listenerArray.indexOf( listener );
   141  
   142  				if ( index !== - 1 ) {
   143  
   144  					listenerArray.splice( index, 1 );
   145  
   146  				}
   147  
   148  			}
   149  
   150  		},
   151  
   152  		dispatchEvent: function ( event ) {
   153  
   154  			if ( this._listeners === undefined ) return;
   155  
   156  			var listeners = this._listeners;
   157  			var listenerArray = listeners[ event.type ];
   158  
   159  			if ( listenerArray !== undefined ) {
   160  
   161  				event.target = this;
   162  
   163  				var array = [], i = 0;
   164  				var length = listenerArray.length;
   165  
   166  				for ( i = 0; i < length; i ++ ) {
   167  
   168  					array[ i ] = listenerArray[ i ];
   169  
   170  				}
   171  
   172  				for ( i = 0; i < length; i ++ ) {
   173  
   174  					array[ i ].call( this, event );
   175  
   176  				}
   177  
   178  			}
   179  
   180  		}
   181  
   182  	};
   183  
   184  	var REVISION = '84';
   185  	var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };
   186  	var CullFaceNone = 0;
   187  	var CullFaceBack = 1;
   188  	var CullFaceFront = 2;
   189  	var CullFaceFrontBack = 3;
   190  	var FrontFaceDirectionCW = 0;
   191  	var FrontFaceDirectionCCW = 1;
   192  	var BasicShadowMap = 0;
   193  	var PCFShadowMap = 1;
   194  	var PCFSoftShadowMap = 2;
   195  	var FrontSide = 0;
   196  	var BackSide = 1;
   197  	var DoubleSide = 2;
   198  	var FlatShading = 1;
   199  	var SmoothShading = 2;
   200  	var NoColors = 0;
   201  	var FaceColors = 1;
   202  	var VertexColors = 2;
   203  	var NoBlending = 0;
   204  	var NormalBlending = 1;
   205  	var AdditiveBlending = 2;
   206  	var SubtractiveBlending = 3;
   207  	var MultiplyBlending = 4;
   208  	var CustomBlending = 5;
   209  	var AddEquation = 100;
   210  	var SubtractEquation = 101;
   211  	var ReverseSubtractEquation = 102;
   212  	var MinEquation = 103;
   213  	var MaxEquation = 104;
   214  	var ZeroFactor = 200;
   215  	var OneFactor = 201;
   216  	var SrcColorFactor = 202;
   217  	var OneMinusSrcColorFactor = 203;
   218  	var SrcAlphaFactor = 204;
   219  	var OneMinusSrcAlphaFactor = 205;
   220  	var DstAlphaFactor = 206;
   221  	var OneMinusDstAlphaFactor = 207;
   222  	var DstColorFactor = 208;
   223  	var OneMinusDstColorFactor = 209;
   224  	var SrcAlphaSaturateFactor = 210;
   225  	var NeverDepth = 0;
   226  	var AlwaysDepth = 1;
   227  	var LessDepth = 2;
   228  	var LessEqualDepth = 3;
   229  	var EqualDepth = 4;
   230  	var GreaterEqualDepth = 5;
   231  	var GreaterDepth = 6;
   232  	var NotEqualDepth = 7;
   233  	var MultiplyOperation = 0;
   234  	var MixOperation = 1;
   235  	var AddOperation = 2;
   236  	var NoToneMapping = 0;
   237  	var LinearToneMapping = 1;
   238  	var ReinhardToneMapping = 2;
   239  	var Uncharted2ToneMapping = 3;
   240  	var CineonToneMapping = 4;
   241  	var UVMapping = 300;
   242  	var CubeReflectionMapping = 301;
   243  	var CubeRefractionMapping = 302;
   244  	var EquirectangularReflectionMapping = 303;
   245  	var EquirectangularRefractionMapping = 304;
   246  	var SphericalReflectionMapping = 305;
   247  	var CubeUVReflectionMapping = 306;
   248  	var CubeUVRefractionMapping = 307;
   249  	var RepeatWrapping = 1000;
   250  	var ClampToEdgeWrapping = 1001;
   251  	var MirroredRepeatWrapping = 1002;
   252  	var NearestFilter = 1003;
   253  	var NearestMipMapNearestFilter = 1004;
   254  	var NearestMipMapLinearFilter = 1005;
   255  	var LinearFilter = 1006;
   256  	var LinearMipMapNearestFilter = 1007;
   257  	var LinearMipMapLinearFilter = 1008;
   258  	var UnsignedByteType = 1009;
   259  	var ByteType = 1010;
   260  	var ShortType = 1011;
   261  	var UnsignedShortType = 1012;
   262  	var IntType = 1013;
   263  	var UnsignedIntType = 1014;
   264  	var FloatType = 1015;
   265  	var HalfFloatType = 1016;
   266  	var UnsignedShort4444Type = 1017;
   267  	var UnsignedShort5551Type = 1018;
   268  	var UnsignedShort565Type = 1019;
   269  	var UnsignedInt248Type = 1020;
   270  	var AlphaFormat = 1021;
   271  	var RGBFormat = 1022;
   272  	var RGBAFormat = 1023;
   273  	var LuminanceFormat = 1024;
   274  	var LuminanceAlphaFormat = 1025;
   275  	var RGBEFormat = RGBAFormat;
   276  	var DepthFormat = 1026;
   277  	var DepthStencilFormat = 1027;
   278  	var RGB_S3TC_DXT1_Format = 2001;
   279  	var RGBA_S3TC_DXT1_Format = 2002;
   280  	var RGBA_S3TC_DXT3_Format = 2003;
   281  	var RGBA_S3TC_DXT5_Format = 2004;
   282  	var RGB_PVRTC_4BPPV1_Format = 2100;
   283  	var RGB_PVRTC_2BPPV1_Format = 2101;
   284  	var RGBA_PVRTC_4BPPV1_Format = 2102;
   285  	var RGBA_PVRTC_2BPPV1_Format = 2103;
   286  	var RGB_ETC1_Format = 2151;
   287  	var LoopOnce = 2200;
   288  	var LoopRepeat = 2201;
   289  	var LoopPingPong = 2202;
   290  	var InterpolateDiscrete = 2300;
   291  	var InterpolateLinear = 2301;
   292  	var InterpolateSmooth = 2302;
   293  	var ZeroCurvatureEnding = 2400;
   294  	var ZeroSlopeEnding = 2401;
   295  	var WrapAroundEnding = 2402;
   296  	var TrianglesDrawMode = 0;
   297  	var TriangleStripDrawMode = 1;
   298  	var TriangleFanDrawMode = 2;
   299  	var LinearEncoding = 3000;
   300  	var sRGBEncoding = 3001;
   301  	var GammaEncoding = 3007;
   302  	var RGBEEncoding = 3002;
   303  	var LogLuvEncoding = 3003;
   304  	var RGBM7Encoding = 3004;
   305  	var RGBM16Encoding = 3005;
   306  	var RGBDEncoding = 3006;
   307  	var BasicDepthPacking = 3200;
   308  	var RGBADepthPacking = 3201;
   309  
   310  	/**
   311  	 * @author alteredq / http://alteredqualia.com/
   312  	 * @author mrdoob / http://mrdoob.com/
   313  	 */
   314  
   315  	var _Math = {
   316  
   317  		DEG2RAD: Math.PI / 180,
   318  		RAD2DEG: 180 / Math.PI,
   319  
   320  		generateUUID: function () {
   321  
   322  			// http://www.broofa.com/Tools/Math.uuid.htm
   323  
   324  			var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' );
   325  			var uuid = new Array( 36 );
   326  			var rnd = 0, r;
   327  
   328  			return function generateUUID() {
   329  
   330  				for ( var i = 0; i < 36; i ++ ) {
   331  
   332  					if ( i === 8 || i === 13 || i === 18 || i === 23 ) {
   333  
   334  						uuid[ i ] = '-';
   335  
   336  					} else if ( i === 14 ) {
   337  
   338  						uuid[ i ] = '4';
   339  
   340  					} else {
   341  
   342  						if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;
   343  						r = rnd & 0xf;
   344  						rnd = rnd >> 4;
   345  						uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ];
   346  
   347  					}
   348  
   349  				}
   350  
   351  				return uuid.join( '' );
   352  
   353  			};
   354  
   355  		}(),
   356  
   357  		clamp: function ( value, min, max ) {
   358  
   359  			return Math.max( min, Math.min( max, value ) );
   360  
   361  		},
   362  
   363  		// compute euclidian modulo of m % n
   364  		// https://en.wikipedia.org/wiki/Modulo_operation
   365  
   366  		euclideanModulo: function ( n, m ) {
   367  
   368  			return ( ( n % m ) + m ) % m;
   369  
   370  		},
   371  
   372  		// Linear mapping from range <a1, a2> to range <b1, b2>
   373  
   374  		mapLinear: function ( x, a1, a2, b1, b2 ) {
   375  
   376  			return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
   377  
   378  		},
   379  
   380  		// https://en.wikipedia.org/wiki/Linear_interpolation
   381  
   382  		lerp: function ( x, y, t ) {
   383  
   384  			return ( 1 - t ) * x + t * y;
   385  
   386  		},
   387  
   388  		// http://en.wikipedia.org/wiki/Smoothstep
   389  
   390  		smoothstep: function ( x, min, max ) {
   391  
   392  			if ( x <= min ) return 0;
   393  			if ( x >= max ) return 1;
   394  
   395  			x = ( x - min ) / ( max - min );
   396  
   397  			return x * x * ( 3 - 2 * x );
   398  
   399  		},
   400  
   401  		smootherstep: function ( x, min, max ) {
   402  
   403  			if ( x <= min ) return 0;
   404  			if ( x >= max ) return 1;
   405  
   406  			x = ( x - min ) / ( max - min );
   407  
   408  			return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
   409  
   410  		},
   411  
   412  		// Random integer from <low, high> interval
   413  
   414  		randInt: function ( low, high ) {
   415  
   416  			return low + Math.floor( Math.random() * ( high - low + 1 ) );
   417  
   418  		},
   419  
   420  		// Random float from <low, high> interval
   421  
   422  		randFloat: function ( low, high ) {
   423  
   424  			return low + Math.random() * ( high - low );
   425  
   426  		},
   427  
   428  		// Random float from <-range/2, range/2> interval
   429  
   430  		randFloatSpread: function ( range ) {
   431  
   432  			return range * ( 0.5 - Math.random() );
   433  
   434  		},
   435  
   436  		degToRad: function ( degrees ) {
   437  
   438  			return degrees * _Math.DEG2RAD;
   439  
   440  		},
   441  
   442  		radToDeg: function ( radians ) {
   443  
   444  			return radians * _Math.RAD2DEG;
   445  
   446  		},
   447  
   448  		isPowerOfTwo: function ( value ) {
   449  
   450  			return ( value & ( value - 1 ) ) === 0 && value !== 0;
   451  
   452  		},
   453  
   454  		nearestPowerOfTwo: function ( value ) {
   455  
   456  			return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) );
   457  
   458  		},
   459  
   460  		nextPowerOfTwo: function ( value ) {
   461  
   462  			value --;
   463  			value |= value >> 1;
   464  			value |= value >> 2;
   465  			value |= value >> 4;
   466  			value |= value >> 8;
   467  			value |= value >> 16;
   468  			value ++;
   469  
   470  			return value;
   471  
   472  		}
   473  
   474  	};
   475  
   476  	/**
   477  	 * @author mrdoob / http://mrdoob.com/
   478  	 * @author philogb / http://blog.thejit.org/
   479  	 * @author egraether / http://egraether.com/
   480  	 * @author zz85 / http://www.lab4games.net/zz85/blog
   481  	 */
   482  
   483  	function Vector2( x, y ) {
   484  
   485  		this.x = x || 0;
   486  		this.y = y || 0;
   487  
   488  	}
   489  
   490  	Vector2.prototype = {
   491  
   492  		constructor: Vector2,
   493  
   494  		isVector2: true,
   495  
   496  		get width() {
   497  
   498  			return this.x;
   499  
   500  		},
   501  
   502  		set width( value ) {
   503  
   504  			this.x = value;
   505  
   506  		},
   507  
   508  		get height() {
   509  
   510  			return this.y;
   511  
   512  		},
   513  
   514  		set height( value ) {
   515  
   516  			this.y = value;
   517  
   518  		},
   519  
   520  		//
   521  
   522  		set: function ( x, y ) {
   523  
   524  			this.x = x;
   525  			this.y = y;
   526  
   527  			return this;
   528  
   529  		},
   530  
   531  		setScalar: function ( scalar ) {
   532  
   533  			this.x = scalar;
   534  			this.y = scalar;
   535  
   536  			return this;
   537  
   538  		},
   539  
   540  		setX: function ( x ) {
   541  
   542  			this.x = x;
   543  
   544  			return this;
   545  
   546  		},
   547  
   548  		setY: function ( y ) {
   549  
   550  			this.y = y;
   551  
   552  			return this;
   553  
   554  		},
   555  
   556  		setComponent: function ( index, value ) {
   557  
   558  			switch ( index ) {
   559  
   560  				case 0: this.x = value; break;
   561  				case 1: this.y = value; break;
   562  				default: throw new Error( 'index is out of range: ' + index );
   563  
   564  			}
   565  
   566  			return this;
   567  
   568  		},
   569  
   570  		getComponent: function ( index ) {
   571  
   572  			switch ( index ) {
   573  
   574  				case 0: return this.x;
   575  				case 1: return this.y;
   576  				default: throw new Error( 'index is out of range: ' + index );
   577  
   578  			}
   579  
   580  		},
   581  
   582  		clone: function () {
   583  
   584  			return new this.constructor( this.x, this.y );
   585  
   586  		},
   587  
   588  		copy: function ( v ) {
   589  
   590  			this.x = v.x;
   591  			this.y = v.y;
   592  
   593  			return this;
   594  
   595  		},
   596  
   597  		add: function ( v, w ) {
   598  
   599  			if ( w !== undefined ) {
   600  
   601  				console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
   602  				return this.addVectors( v, w );
   603  
   604  			}
   605  
   606  			this.x += v.x;
   607  			this.y += v.y;
   608  
   609  			return this;
   610  
   611  		},
   612  
   613  		addScalar: function ( s ) {
   614  
   615  			this.x += s;
   616  			this.y += s;
   617  
   618  			return this;
   619  
   620  		},
   621  
   622  		addVectors: function ( a, b ) {
   623  
   624  			this.x = a.x + b.x;
   625  			this.y = a.y + b.y;
   626  
   627  			return this;
   628  
   629  		},
   630  
   631  		addScaledVector: function ( v, s ) {
   632  
   633  			this.x += v.x * s;
   634  			this.y += v.y * s;
   635  
   636  			return this;
   637  
   638  		},
   639  
   640  		sub: function ( v, w ) {
   641  
   642  			if ( w !== undefined ) {
   643  
   644  				console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
   645  				return this.subVectors( v, w );
   646  
   647  			}
   648  
   649  			this.x -= v.x;
   650  			this.y -= v.y;
   651  
   652  			return this;
   653  
   654  		},
   655  
   656  		subScalar: function ( s ) {
   657  
   658  			this.x -= s;
   659  			this.y -= s;
   660  
   661  			return this;
   662  
   663  		},
   664  
   665  		subVectors: function ( a, b ) {
   666  
   667  			this.x = a.x - b.x;
   668  			this.y = a.y - b.y;
   669  
   670  			return this;
   671  
   672  		},
   673  
   674  		multiply: function ( v ) {
   675  
   676  			this.x *= v.x;
   677  			this.y *= v.y;
   678  
   679  			return this;
   680  
   681  		},
   682  
   683  		multiplyScalar: function ( scalar ) {
   684  
   685  			if ( isFinite( scalar ) ) {
   686  
   687  				this.x *= scalar;
   688  				this.y *= scalar;
   689  
   690  			} else {
   691  
   692  				this.x = 0;
   693  				this.y = 0;
   694  
   695  			}
   696  
   697  			return this;
   698  
   699  		},
   700  
   701  		divide: function ( v ) {
   702  
   703  			this.x /= v.x;
   704  			this.y /= v.y;
   705  
   706  			return this;
   707  
   708  		},
   709  
   710  		divideScalar: function ( scalar ) {
   711  
   712  			return this.multiplyScalar( 1 / scalar );
   713  
   714  		},
   715  
   716  		min: function ( v ) {
   717  
   718  			this.x = Math.min( this.x, v.x );
   719  			this.y = Math.min( this.y, v.y );
   720  
   721  			return this;
   722  
   723  		},
   724  
   725  		max: function ( v ) {
   726  
   727  			this.x = Math.max( this.x, v.x );
   728  			this.y = Math.max( this.y, v.y );
   729  
   730  			return this;
   731  
   732  		},
   733  
   734  		clamp: function ( min, max ) {
   735  
   736  			// This function assumes min < max, if this assumption isn't true it will not operate correctly
   737  
   738  			this.x = Math.max( min.x, Math.min( max.x, this.x ) );
   739  			this.y = Math.max( min.y, Math.min( max.y, this.y ) );
   740  
   741  			return this;
   742  
   743  		},
   744  
   745  		clampScalar: function () {
   746  
   747  			var min, max;
   748  
   749  			return function clampScalar( minVal, maxVal ) {
   750  
   751  				if ( min === undefined ) {
   752  
   753  					min = new Vector2();
   754  					max = new Vector2();
   755  
   756  				}
   757  
   758  				min.set( minVal, minVal );
   759  				max.set( maxVal, maxVal );
   760  
   761  				return this.clamp( min, max );
   762  
   763  			};
   764  
   765  		}(),
   766  
   767  		clampLength: function ( min, max ) {
   768  
   769  			var length = this.length();
   770  
   771  			return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length );
   772  
   773  		},
   774  
   775  		floor: function () {
   776  
   777  			this.x = Math.floor( this.x );
   778  			this.y = Math.floor( this.y );
   779  
   780  			return this;
   781  
   782  		},
   783  
   784  		ceil: function () {
   785  
   786  			this.x = Math.ceil( this.x );
   787  			this.y = Math.ceil( this.y );
   788  
   789  			return this;
   790  
   791  		},
   792  
   793  		round: function () {
   794  
   795  			this.x = Math.round( this.x );
   796  			this.y = Math.round( this.y );
   797  
   798  			return this;
   799  
   800  		},
   801  
   802  		roundToZero: function () {
   803  
   804  			this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
   805  			this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
   806  
   807  			return this;
   808  
   809  		},
   810  
   811  		negate: function () {
   812  
   813  			this.x = - this.x;
   814  			this.y = - this.y;
   815  
   816  			return this;
   817  
   818  		},
   819  
   820  		dot: function ( v ) {
   821  
   822  			return this.x * v.x + this.y * v.y;
   823  
   824  		},
   825  
   826  		lengthSq: function () {
   827  
   828  			return this.x * this.x + this.y * this.y;
   829  
   830  		},
   831  
   832  		length: function () {
   833  
   834  			return Math.sqrt( this.x * this.x + this.y * this.y );
   835  
   836  		},
   837  
   838  		lengthManhattan: function() {
   839  
   840  			return Math.abs( this.x ) + Math.abs( this.y );
   841  
   842  		},
   843  
   844  		normalize: function () {
   845  
   846  			return this.divideScalar( this.length() );
   847  
   848  		},
   849  
   850  		angle: function () {
   851  
   852  			// computes the angle in radians with respect to the positive x-axis
   853  
   854  			var angle = Math.atan2( this.y, this.x );
   855  
   856  			if ( angle < 0 ) angle += 2 * Math.PI;
   857  
   858  			return angle;
   859  
   860  		},
   861  
   862  		distanceTo: function ( v ) {
   863  
   864  			return Math.sqrt( this.distanceToSquared( v ) );
   865  
   866  		},
   867  
   868  		distanceToSquared: function ( v ) {
   869  
   870  			var dx = this.x - v.x, dy = this.y - v.y;
   871  			return dx * dx + dy * dy;
   872  
   873  		},
   874  
   875  		distanceToManhattan: function ( v ) {
   876  
   877  			return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
   878  
   879  		},
   880  
   881  		setLength: function ( length ) {
   882  
   883  			return this.multiplyScalar( length / this.length() );
   884  
   885  		},
   886  
   887  		lerp: function ( v, alpha ) {
   888  
   889  			this.x += ( v.x - this.x ) * alpha;
   890  			this.y += ( v.y - this.y ) * alpha;
   891  
   892  			return this;
   893  
   894  		},
   895  
   896  		lerpVectors: function ( v1, v2, alpha ) {
   897  
   898  			return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
   899  
   900  		},
   901  
   902  		equals: function ( v ) {
   903  
   904  			return ( ( v.x === this.x ) && ( v.y === this.y ) );
   905  
   906  		},
   907  
   908  		fromArray: function ( array, offset ) {
   909  
   910  			if ( offset === undefined ) offset = 0;
   911  
   912  			this.x = array[ offset ];
   913  			this.y = array[ offset + 1 ];
   914  
   915  			return this;
   916  
   917  		},
   918  
   919  		toArray: function ( array, offset ) {
   920  
   921  			if ( array === undefined ) array = [];
   922  			if ( offset === undefined ) offset = 0;
   923  
   924  			array[ offset ] = this.x;
   925  			array[ offset + 1 ] = this.y;
   926  
   927  			return array;
   928  
   929  		},
   930  
   931  		fromBufferAttribute: function ( attribute, index, offset ) {
   932  
   933  			if ( offset !== undefined ) {
   934  
   935  				console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );
   936  
   937  			}
   938  
   939  			this.x = attribute.getX( index );
   940  			this.y = attribute.getY( index );
   941  
   942  			return this;
   943  
   944  		},
   945  
   946  		rotateAround: function ( center, angle ) {
   947  
   948  			var c = Math.cos( angle ), s = Math.sin( angle );
   949  
   950  			var x = this.x - center.x;
   951  			var y = this.y - center.y;
   952  
   953  			this.x = x * c - y * s + center.x;
   954  			this.y = x * s + y * c + center.y;
   955  
   956  			return this;
   957  
   958  		}
   959  
   960  	};
   961  
   962  	/**
   963  	 * @author mrdoob / http://mrdoob.com/
   964  	 * @author alteredq / http://alteredqualia.com/
   965  	 * @author szimek / https://github.com/szimek/
   966  	 */
   967  
   968  	var textureId = 0;
   969  
   970  	function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
   971  
   972  		Object.defineProperty( this, 'id', { value: textureId ++ } );
   973  
   974  		this.uuid = _Math.generateUUID();
   975  
   976  		this.name = '';
   977  
   978  		this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE;
   979  		this.mipmaps = [];
   980  
   981  		this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING;
   982  
   983  		this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping;
   984  		this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping;
   985  
   986  		this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
   987  		this.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter;
   988  
   989  		this.anisotropy = anisotropy !== undefined ? anisotropy : 1;
   990  
   991  		this.format = format !== undefined ? format : RGBAFormat;
   992  		this.type = type !== undefined ? type : UnsignedByteType;
   993  
   994  		this.offset = new Vector2( 0, 0 );
   995  		this.repeat = new Vector2( 1, 1 );
   996  
   997  		this.generateMipmaps = true;
   998  		this.premultiplyAlpha = false;
   999  		this.flipY = true;
  1000  		this.unpackAlignment = 4;	// valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
  1001  
  1002  
  1003  		// Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
  1004  		//
  1005  		// Also changing the encoding after already used by a Material will not automatically make the Material
  1006  		// update.  You need to explicitly call Material.needsUpdate to trigger it to recompile.
  1007  		this.encoding = encoding !== undefined ? encoding : LinearEncoding;
  1008  
  1009  		this.version = 0;
  1010  		this.onUpdate = null;
  1011  
  1012  	}
  1013  
  1014  	Texture.DEFAULT_IMAGE = undefined;
  1015  	Texture.DEFAULT_MAPPING = UVMapping;
  1016  
  1017  	Texture.prototype = {
  1018  
  1019  		constructor: Texture,
  1020  
  1021  		isTexture: true,
  1022  
  1023  		set needsUpdate( value ) {
  1024  
  1025  			if ( value === true ) this.version ++;
  1026  
  1027  		},
  1028  
  1029  		clone: function () {
  1030  
  1031  			return new this.constructor().copy( this );
  1032  
  1033  		},
  1034  
  1035  		copy: function ( source ) {
  1036  
  1037  			this.image = source.image;
  1038  			this.mipmaps = source.mipmaps.slice( 0 );
  1039  
  1040  			this.mapping = source.mapping;
  1041  
  1042  			this.wrapS = source.wrapS;
  1043  			this.wrapT = source.wrapT;
  1044  
  1045  			this.magFilter = source.magFilter;
  1046  			this.minFilter = source.minFilter;
  1047  
  1048  			this.anisotropy = source.anisotropy;
  1049  
  1050  			this.format = source.format;
  1051  			this.type = source.type;
  1052  
  1053  			this.offset.copy( source.offset );
  1054  			this.repeat.copy( source.repeat );
  1055  
  1056  			this.generateMipmaps = source.generateMipmaps;
  1057  			this.premultiplyAlpha = source.premultiplyAlpha;
  1058  			this.flipY = source.flipY;
  1059  			this.unpackAlignment = source.unpackAlignment;
  1060  			this.encoding = source.encoding;
  1061  
  1062  			return this;
  1063  
  1064  		},
  1065  
  1066  		toJSON: function ( meta ) {
  1067  
  1068  			if ( meta.textures[ this.uuid ] !== undefined ) {
  1069  
  1070  				return meta.textures[ this.uuid ];
  1071  
  1072  			}
  1073  
  1074  			function getDataURL( image ) {
  1075  
  1076  				var canvas;
  1077  
  1078  				if ( image.toDataURL !== undefined ) {
  1079  
  1080  					canvas = image;
  1081  
  1082  				} else {
  1083  
  1084  					canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
  1085  					canvas.width = image.width;
  1086  					canvas.height = image.height;
  1087  
  1088  					canvas.getContext( '2d' ).drawImage( image, 0, 0, image.width, image.height );
  1089  
  1090  				}
  1091  
  1092  				if ( canvas.width > 2048 || canvas.height > 2048 ) {
  1093  
  1094  					return canvas.toDataURL( 'image/jpeg', 0.6 );
  1095  
  1096  				} else {
  1097  
  1098  					return canvas.toDataURL( 'image/png' );
  1099  
  1100  				}
  1101  
  1102  			}
  1103  
  1104  			var output = {
  1105  				metadata: {
  1106  					version: 4.4,
  1107  					type: 'Texture',
  1108  					generator: 'Texture.toJSON'
  1109  				},
  1110  
  1111  				uuid: this.uuid,
  1112  				name: this.name,
  1113  
  1114  				mapping: this.mapping,
  1115  
  1116  				repeat: [ this.repeat.x, this.repeat.y ],
  1117  				offset: [ this.offset.x, this.offset.y ],
  1118  				wrap: [ this.wrapS, this.wrapT ],
  1119  
  1120  				minFilter: this.minFilter,
  1121  				magFilter: this.magFilter,
  1122  				anisotropy: this.anisotropy,
  1123  
  1124  				flipY: this.flipY
  1125  			};
  1126  
  1127  			if ( this.image !== undefined ) {
  1128  
  1129  				// TODO: Move to THREE.Image
  1130  
  1131  				var image = this.image;
  1132  
  1133  				if ( image.uuid === undefined ) {
  1134  
  1135  					image.uuid = _Math.generateUUID(); // UGH
  1136  
  1137  				}
  1138  
  1139  				if ( meta.images[ image.uuid ] === undefined ) {
  1140  
  1141  					meta.images[ image.uuid ] = {
  1142  						uuid: image.uuid,
  1143  						url: getDataURL( image )
  1144  					};
  1145  
  1146  				}
  1147  
  1148  				output.image = image.uuid;
  1149  
  1150  			}
  1151  
  1152  			meta.textures[ this.uuid ] = output;
  1153  
  1154  			return output;
  1155  
  1156  		},
  1157  
  1158  		dispose: function () {
  1159  
  1160  			this.dispatchEvent( { type: 'dispose' } );
  1161  
  1162  		},
  1163  
  1164  		transformUv: function ( uv ) {
  1165  
  1166  			if ( this.mapping !== UVMapping ) return;
  1167  
  1168  			uv.multiply( this.repeat );
  1169  			uv.add( this.offset );
  1170  
  1171  			if ( uv.x < 0 || uv.x > 1 ) {
  1172  
  1173  				switch ( this.wrapS ) {
  1174  
  1175  					case RepeatWrapping:
  1176  
  1177  						uv.x = uv.x - Math.floor( uv.x );
  1178  						break;
  1179  
  1180  					case ClampToEdgeWrapping:
  1181  
  1182  						uv.x = uv.x < 0 ? 0 : 1;
  1183  						break;
  1184  
  1185  					case MirroredRepeatWrapping:
  1186  
  1187  						if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
  1188  
  1189  							uv.x = Math.ceil( uv.x ) - uv.x;
  1190  
  1191  						} else {
  1192  
  1193  							uv.x = uv.x - Math.floor( uv.x );
  1194  
  1195  						}
  1196  						break;
  1197  
  1198  				}
  1199  
  1200  			}
  1201  
  1202  			if ( uv.y < 0 || uv.y > 1 ) {
  1203  
  1204  				switch ( this.wrapT ) {
  1205  
  1206  					case RepeatWrapping:
  1207  
  1208  						uv.y = uv.y - Math.floor( uv.y );
  1209  						break;
  1210  
  1211  					case ClampToEdgeWrapping:
  1212  
  1213  						uv.y = uv.y < 0 ? 0 : 1;
  1214  						break;
  1215  
  1216  					case MirroredRepeatWrapping:
  1217  
  1218  						if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
  1219  
  1220  							uv.y = Math.ceil( uv.y ) - uv.y;
  1221  
  1222  						} else {
  1223  
  1224  							uv.y = uv.y - Math.floor( uv.y );
  1225  
  1226  						}
  1227  						break;
  1228  
  1229  				}
  1230  
  1231  			}
  1232  
  1233  			if ( this.flipY ) {
  1234  
  1235  				uv.y = 1 - uv.y;
  1236  
  1237  			}
  1238  
  1239  		}
  1240  
  1241  	};
  1242  
  1243  	Object.assign( Texture.prototype, EventDispatcher.prototype );
  1244  
  1245  	/**
  1246  	 * @author supereggbert / http://www.paulbrunt.co.uk/
  1247  	 * @author philogb / http://blog.thejit.org/
  1248  	 * @author mikael emtinger / http://gomo.se/
  1249  	 * @author egraether / http://egraether.com/
  1250  	 * @author WestLangley / http://github.com/WestLangley
  1251  	 */
  1252  
  1253  	function Vector4( x, y, z, w ) {
  1254  
  1255  		this.x = x || 0;
  1256  		this.y = y || 0;
  1257  		this.z = z || 0;
  1258  		this.w = ( w !== undefined ) ? w : 1;
  1259  
  1260  	}
  1261  
  1262  	Vector4.prototype = {
  1263  
  1264  		constructor: Vector4,
  1265  
  1266  		isVector4: true,
  1267  
  1268  		set: function ( x, y, z, w ) {
  1269  
  1270  			this.x = x;
  1271  			this.y = y;
  1272  			this.z = z;
  1273  			this.w = w;
  1274  
  1275  			return this;
  1276  
  1277  		},
  1278  
  1279  		setScalar: function ( scalar ) {
  1280  
  1281  			this.x = scalar;
  1282  			this.y = scalar;
  1283  			this.z = scalar;
  1284  			this.w = scalar;
  1285  
  1286  			return this;
  1287  
  1288  		},
  1289  
  1290  		setX: function ( x ) {
  1291  
  1292  			this.x = x;
  1293  
  1294  			return this;
  1295  
  1296  		},
  1297  
  1298  		setY: function ( y ) {
  1299  
  1300  			this.y = y;
  1301  
  1302  			return this;
  1303  
  1304  		},
  1305  
  1306  		setZ: function ( z ) {
  1307  
  1308  			this.z = z;
  1309  
  1310  			return this;
  1311  
  1312  		},
  1313  
  1314  		setW: function ( w ) {
  1315  
  1316  			this.w = w;
  1317  
  1318  			return this;
  1319  
  1320  		},
  1321  
  1322  		setComponent: function ( index, value ) {
  1323  
  1324  			switch ( index ) {
  1325  
  1326  				case 0: this.x = value; break;
  1327  				case 1: this.y = value; break;
  1328  				case 2: this.z = value; break;
  1329  				case 3: this.w = value; break;
  1330  				default: throw new Error( 'index is out of range: ' + index );
  1331  
  1332  			}
  1333  
  1334  			return this;
  1335  
  1336  		},
  1337  
  1338  		getComponent: function ( index ) {
  1339  
  1340  			switch ( index ) {
  1341  
  1342  				case 0: return this.x;
  1343  				case 1: return this.y;
  1344  				case 2: return this.z;
  1345  				case 3: return this.w;
  1346  				default: throw new Error( 'index is out of range: ' + index );
  1347  
  1348  			}
  1349  
  1350  		},
  1351  
  1352  		clone: function () {
  1353  
  1354  			return new this.constructor( this.x, this.y, this.z, this.w );
  1355  
  1356  		},
  1357  
  1358  		copy: function ( v ) {
  1359  
  1360  			this.x = v.x;
  1361  			this.y = v.y;
  1362  			this.z = v.z;
  1363  			this.w = ( v.w !== undefined ) ? v.w : 1;
  1364  
  1365  			return this;
  1366  
  1367  		},
  1368  
  1369  		add: function ( v, w ) {
  1370  
  1371  			if ( w !== undefined ) {
  1372  
  1373  				console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
  1374  				return this.addVectors( v, w );
  1375  
  1376  			}
  1377  
  1378  			this.x += v.x;
  1379  			this.y += v.y;
  1380  			this.z += v.z;
  1381  			this.w += v.w;
  1382  
  1383  			return this;
  1384  
  1385  		},
  1386  
  1387  		addScalar: function ( s ) {
  1388  
  1389  			this.x += s;
  1390  			this.y += s;
  1391  			this.z += s;
  1392  			this.w += s;
  1393  
  1394  			return this;
  1395  
  1396  		},
  1397  
  1398  		addVectors: function ( a, b ) {
  1399  
  1400  			this.x = a.x + b.x;
  1401  			this.y = a.y + b.y;
  1402  			this.z = a.z + b.z;
  1403  			this.w = a.w + b.w;
  1404  
  1405  			return this;
  1406  
  1407  		},
  1408  
  1409  		addScaledVector: function ( v, s ) {
  1410  
  1411  			this.x += v.x * s;
  1412  			this.y += v.y * s;
  1413  			this.z += v.z * s;
  1414  			this.w += v.w * s;
  1415  
  1416  			return this;
  1417  
  1418  		},
  1419  
  1420  		sub: function ( v, w ) {
  1421  
  1422  			if ( w !== undefined ) {
  1423  
  1424  				console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
  1425  				return this.subVectors( v, w );
  1426  
  1427  			}
  1428  
  1429  			this.x -= v.x;
  1430  			this.y -= v.y;
  1431  			this.z -= v.z;
  1432  			this.w -= v.w;
  1433  
  1434  			return this;
  1435  
  1436  		},
  1437  
  1438  		subScalar: function ( s ) {
  1439  
  1440  			this.x -= s;
  1441  			this.y -= s;
  1442  			this.z -= s;
  1443  			this.w -= s;
  1444  
  1445  			return this;
  1446  
  1447  		},
  1448  
  1449  		subVectors: function ( a, b ) {
  1450  
  1451  			this.x = a.x - b.x;
  1452  			this.y = a.y - b.y;
  1453  			this.z = a.z - b.z;
  1454  			this.w = a.w - b.w;
  1455  
  1456  			return this;
  1457  
  1458  		},
  1459  
  1460  		multiplyScalar: function ( scalar ) {
  1461  
  1462  			if ( isFinite( scalar ) ) {
  1463  
  1464  				this.x *= scalar;
  1465  				this.y *= scalar;
  1466  				this.z *= scalar;
  1467  				this.w *= scalar;
  1468  
  1469  			} else {
  1470  
  1471  				this.x = 0;
  1472  				this.y = 0;
  1473  				this.z = 0;
  1474  				this.w = 0;
  1475  
  1476  			}
  1477  
  1478  			return this;
  1479  
  1480  		},
  1481  
  1482  		applyMatrix4: function ( m ) {
  1483  
  1484  			var x = this.x, y = this.y, z = this.z, w = this.w;
  1485  			var e = m.elements;
  1486  
  1487  			this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
  1488  			this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
  1489  			this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
  1490  			this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
  1491  
  1492  			return this;
  1493  
  1494  		},
  1495  
  1496  		divideScalar: function ( scalar ) {
  1497  
  1498  			return this.multiplyScalar( 1 / scalar );
  1499  
  1500  		},
  1501  
  1502  		setAxisAngleFromQuaternion: function ( q ) {
  1503  
  1504  			// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
  1505  
  1506  			// q is assumed to be normalized
  1507  
  1508  			this.w = 2 * Math.acos( q.w );
  1509  
  1510  			var s = Math.sqrt( 1 - q.w * q.w );
  1511  
  1512  			if ( s < 0.0001 ) {
  1513  
  1514  				 this.x = 1;
  1515  				 this.y = 0;
  1516  				 this.z = 0;
  1517  
  1518  			} else {
  1519  
  1520  				 this.x = q.x / s;
  1521  				 this.y = q.y / s;
  1522  				 this.z = q.z / s;
  1523  
  1524  			}
  1525  
  1526  			return this;
  1527  
  1528  		},
  1529  
  1530  		setAxisAngleFromRotationMatrix: function ( m ) {
  1531  
  1532  			// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
  1533  
  1534  			// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  1535  
  1536  			var angle, x, y, z,		// variables for result
  1537  				epsilon = 0.01,		// margin to allow for rounding errors
  1538  				epsilon2 = 0.1,		// margin to distinguish between 0 and 180 degrees
  1539  
  1540  				te = m.elements,
  1541  
  1542  				m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
  1543  				m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
  1544  				m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
  1545  
  1546  			if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
  1547  			     ( Math.abs( m13 - m31 ) < epsilon ) &&
  1548  			     ( Math.abs( m23 - m32 ) < epsilon ) ) {
  1549  
  1550  				// singularity found
  1551  				// first check for identity matrix which must have +1 for all terms
  1552  				// in leading diagonal and zero in other terms
  1553  
  1554  				if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
  1555  				     ( Math.abs( m13 + m31 ) < epsilon2 ) &&
  1556  				     ( Math.abs( m23 + m32 ) < epsilon2 ) &&
  1557  				     ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
  1558  
  1559  					// this singularity is identity matrix so angle = 0
  1560  
  1561  					this.set( 1, 0, 0, 0 );
  1562  
  1563  					return this; // zero angle, arbitrary axis
  1564  
  1565  				}
  1566  
  1567  				// otherwise this singularity is angle = 180
  1568  
  1569  				angle = Math.PI;
  1570  
  1571  				var xx = ( m11 + 1 ) / 2;
  1572  				var yy = ( m22 + 1 ) / 2;
  1573  				var zz = ( m33 + 1 ) / 2;
  1574  				var xy = ( m12 + m21 ) / 4;
  1575  				var xz = ( m13 + m31 ) / 4;
  1576  				var yz = ( m23 + m32 ) / 4;
  1577  
  1578  				if ( ( xx > yy ) && ( xx > zz ) ) {
  1579  
  1580  					// m11 is the largest diagonal term
  1581  
  1582  					if ( xx < epsilon ) {
  1583  
  1584  						x = 0;
  1585  						y = 0.707106781;
  1586  						z = 0.707106781;
  1587  
  1588  					} else {
  1589  
  1590  						x = Math.sqrt( xx );
  1591  						y = xy / x;
  1592  						z = xz / x;
  1593  
  1594  					}
  1595  
  1596  				} else if ( yy > zz ) {
  1597  
  1598  					// m22 is the largest diagonal term
  1599  
  1600  					if ( yy < epsilon ) {
  1601  
  1602  						x = 0.707106781;
  1603  						y = 0;
  1604  						z = 0.707106781;
  1605  
  1606  					} else {
  1607  
  1608  						y = Math.sqrt( yy );
  1609  						x = xy / y;
  1610  						z = yz / y;
  1611  
  1612  					}
  1613  
  1614  				} else {
  1615  
  1616  					// m33 is the largest diagonal term so base result on this
  1617  
  1618  					if ( zz < epsilon ) {
  1619  
  1620  						x = 0.707106781;
  1621  						y = 0.707106781;
  1622  						z = 0;
  1623  
  1624  					} else {
  1625  
  1626  						z = Math.sqrt( zz );
  1627  						x = xz / z;
  1628  						y = yz / z;
  1629  
  1630  					}
  1631  
  1632  				}
  1633  
  1634  				this.set( x, y, z, angle );
  1635  
  1636  				return this; // return 180 deg rotation
  1637  
  1638  			}
  1639  
  1640  			// as we have reached here there are no singularities so we can handle normally
  1641  
  1642  			var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
  1643  			                   ( m13 - m31 ) * ( m13 - m31 ) +
  1644  			                   ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
  1645  
  1646  			if ( Math.abs( s ) < 0.001 ) s = 1;
  1647  
  1648  			// prevent divide by zero, should not happen if matrix is orthogonal and should be
  1649  			// caught by singularity test above, but I've left it in just in case
  1650  
  1651  			this.x = ( m32 - m23 ) / s;
  1652  			this.y = ( m13 - m31 ) / s;
  1653  			this.z = ( m21 - m12 ) / s;
  1654  			this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
  1655  
  1656  			return this;
  1657  
  1658  		},
  1659  
  1660  		min: function ( v ) {
  1661  
  1662  			this.x = Math.min( this.x, v.x );
  1663  			this.y = Math.min( this.y, v.y );
  1664  			this.z = Math.min( this.z, v.z );
  1665  			this.w = Math.min( this.w, v.w );
  1666  
  1667  			return this;
  1668  
  1669  		},
  1670  
  1671  		max: function ( v ) {
  1672  
  1673  			this.x = Math.max( this.x, v.x );
  1674  			this.y = Math.max( this.y, v.y );
  1675  			this.z = Math.max( this.z, v.z );
  1676  			this.w = Math.max( this.w, v.w );
  1677  
  1678  			return this;
  1679  
  1680  		},
  1681  
  1682  		clamp: function ( min, max ) {
  1683  
  1684  			// This function assumes min < max, if this assumption isn't true it will not operate correctly
  1685  
  1686  			this.x = Math.max( min.x, Math.min( max.x, this.x ) );
  1687  			this.y = Math.max( min.y, Math.min( max.y, this.y ) );
  1688  			this.z = Math.max( min.z, Math.min( max.z, this.z ) );
  1689  			this.w = Math.max( min.w, Math.min( max.w, this.w ) );
  1690  
  1691  			return this;
  1692  
  1693  		},
  1694  
  1695  		clampScalar: function () {
  1696  
  1697  			var min, max;
  1698  
  1699  			return function clampScalar( minVal, maxVal ) {
  1700  
  1701  				if ( min === undefined ) {
  1702  
  1703  					min = new Vector4();
  1704  					max = new Vector4();
  1705  
  1706  				}
  1707  
  1708  				min.set( minVal, minVal, minVal, minVal );
  1709  				max.set( maxVal, maxVal, maxVal, maxVal );
  1710  
  1711  				return this.clamp( min, max );
  1712  
  1713  			};
  1714  
  1715  		}(),
  1716  
  1717  		floor: function () {
  1718  
  1719  			this.x = Math.floor( this.x );
  1720  			this.y = Math.floor( this.y );
  1721  			this.z = Math.floor( this.z );
  1722  			this.w = Math.floor( this.w );
  1723  
  1724  			return this;
  1725  
  1726  		},
  1727  
  1728  		ceil: function () {
  1729  
  1730  			this.x = Math.ceil( this.x );
  1731  			this.y = Math.ceil( this.y );
  1732  			this.z = Math.ceil( this.z );
  1733  			this.w = Math.ceil( this.w );
  1734  
  1735  			return this;
  1736  
  1737  		},
  1738  
  1739  		round: function () {
  1740  
  1741  			this.x = Math.round( this.x );
  1742  			this.y = Math.round( this.y );
  1743  			this.z = Math.round( this.z );
  1744  			this.w = Math.round( this.w );
  1745  
  1746  			return this;
  1747  
  1748  		},
  1749  
  1750  		roundToZero: function () {
  1751  
  1752  			this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
  1753  			this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
  1754  			this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
  1755  			this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
  1756  
  1757  			return this;
  1758  
  1759  		},
  1760  
  1761  		negate: function () {
  1762  
  1763  			this.x = - this.x;
  1764  			this.y = - this.y;
  1765  			this.z = - this.z;
  1766  			this.w = - this.w;
  1767  
  1768  			return this;
  1769  
  1770  		},
  1771  
  1772  		dot: function ( v ) {
  1773  
  1774  			return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
  1775  
  1776  		},
  1777  
  1778  		lengthSq: function () {
  1779  
  1780  			return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
  1781  
  1782  		},
  1783  
  1784  		length: function () {
  1785  
  1786  			return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
  1787  
  1788  		},
  1789  
  1790  		lengthManhattan: function () {
  1791  
  1792  			return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
  1793  
  1794  		},
  1795  
  1796  		normalize: function () {
  1797  
  1798  			return this.divideScalar( this.length() );
  1799  
  1800  		},
  1801  
  1802  		setLength: function ( length ) {
  1803  
  1804  			return this.multiplyScalar( length / this.length() );
  1805  
  1806  		},
  1807  
  1808  		lerp: function ( v, alpha ) {
  1809  
  1810  			this.x += ( v.x - this.x ) * alpha;
  1811  			this.y += ( v.y - this.y ) * alpha;
  1812  			this.z += ( v.z - this.z ) * alpha;
  1813  			this.w += ( v.w - this.w ) * alpha;
  1814  
  1815  			return this;
  1816  
  1817  		},
  1818  
  1819  		lerpVectors: function ( v1, v2, alpha ) {
  1820  
  1821  			return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
  1822  
  1823  		},
  1824  
  1825  		equals: function ( v ) {
  1826  
  1827  			return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
  1828  
  1829  		},
  1830  
  1831  		fromArray: function ( array, offset ) {
  1832  
  1833  			if ( offset === undefined ) offset = 0;
  1834  
  1835  			this.x = array[ offset ];
  1836  			this.y = array[ offset + 1 ];
  1837  			this.z = array[ offset + 2 ];
  1838  			this.w = array[ offset + 3 ];
  1839  
  1840  			return this;
  1841  
  1842  		},
  1843  
  1844  		toArray: function ( array, offset ) {
  1845  
  1846  			if ( array === undefined ) array = [];
  1847  			if ( offset === undefined ) offset = 0;
  1848  
  1849  			array[ offset ] = this.x;
  1850  			array[ offset + 1 ] = this.y;
  1851  			array[ offset + 2 ] = this.z;
  1852  			array[ offset + 3 ] = this.w;
  1853  
  1854  			return array;
  1855  
  1856  		},
  1857  
  1858  		fromBufferAttribute: function ( attribute, index, offset ) {
  1859  
  1860  			if ( offset !== undefined ) {
  1861  
  1862  				console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );
  1863  
  1864  			}
  1865  
  1866  			this.x = attribute.getX( index );
  1867  			this.y = attribute.getY( index );
  1868  			this.z = attribute.getZ( index );
  1869  			this.w = attribute.getW( index );
  1870  
  1871  			return this;
  1872  
  1873  		}
  1874  
  1875  	};
  1876  
  1877  	/**
  1878  	 * @author szimek / https://github.com/szimek/
  1879  	 * @author alteredq / http://alteredqualia.com/
  1880  	 * @author Marius Kintel / https://github.com/kintel
  1881  	 */
  1882  
  1883  	/*
  1884  	 In options, we can specify:
  1885  	 * Texture parameters for an auto-generated target texture
  1886  	 * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
  1887  	*/
  1888  	function WebGLRenderTarget( width, height, options ) {
  1889  
  1890  		this.uuid = _Math.generateUUID();
  1891  
  1892  		this.width = width;
  1893  		this.height = height;
  1894  
  1895  		this.scissor = new Vector4( 0, 0, width, height );
  1896  		this.scissorTest = false;
  1897  
  1898  		this.viewport = new Vector4( 0, 0, width, height );
  1899  
  1900  		options = options || {};
  1901  
  1902  		if ( options.minFilter === undefined ) options.minFilter = LinearFilter;
  1903  
  1904  		this.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
  1905  
  1906  		this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
  1907  		this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;
  1908  		this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;
  1909  
  1910  	}
  1911  
  1912  	WebGLRenderTarget.prototype = {
  1913  
  1914  		constructor: WebGLRenderTarget,
  1915  
  1916  		isWebGLRenderTarget: true,
  1917  
  1918  		setSize: function ( width, height ) {
  1919  
  1920  			if ( this.width !== width || this.height !== height ) {
  1921  
  1922  				this.width = width;
  1923  				this.height = height;
  1924  
  1925  				this.dispose();
  1926  
  1927  			}
  1928  
  1929  			this.viewport.set( 0, 0, width, height );
  1930  			this.scissor.set( 0, 0, width, height );
  1931  
  1932  		},
  1933  
  1934  		clone: function () {
  1935  
  1936  			return new this.constructor().copy( this );
  1937  
  1938  		},
  1939  
  1940  		copy: function ( source ) {
  1941  
  1942  			this.width = source.width;
  1943  			this.height = source.height;
  1944  
  1945  			this.viewport.copy( source.viewport );
  1946  
  1947  			this.texture = source.texture.clone();
  1948  
  1949  			this.depthBuffer = source.depthBuffer;
  1950  			this.stencilBuffer = source.stencilBuffer;
  1951  			this.depthTexture = source.depthTexture;
  1952  
  1953  			return this;
  1954  
  1955  		},
  1956  
  1957  		dispose: function () {
  1958  
  1959  			this.dispatchEvent( { type: 'dispose' } );
  1960  
  1961  		}
  1962  
  1963  	};
  1964  
  1965  	Object.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype );
  1966  
  1967  	/**
  1968  	 * @author alteredq / http://alteredqualia.com
  1969  	 */
  1970  
  1971  	function WebGLRenderTargetCube( width, height, options ) {
  1972  
  1973  		WebGLRenderTarget.call( this, width, height, options );
  1974  
  1975  		this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5
  1976  		this.activeMipMapLevel = 0;
  1977  
  1978  	}
  1979  
  1980  	WebGLRenderTargetCube.prototype = Object.create( WebGLRenderTarget.prototype );
  1981  	WebGLRenderTargetCube.prototype.constructor = WebGLRenderTargetCube;
  1982  
  1983  	WebGLRenderTargetCube.prototype.isWebGLRenderTargetCube = true;
  1984  
  1985  	/**
  1986  	 * @author mikael emtinger / http://gomo.se/
  1987  	 * @author alteredq / http://alteredqualia.com/
  1988  	 * @author WestLangley / http://github.com/WestLangley
  1989  	 * @author bhouston / http://clara.io
  1990  	 */
  1991  
  1992  	function Quaternion( x, y, z, w ) {
  1993  
  1994  		this._x = x || 0;
  1995  		this._y = y || 0;
  1996  		this._z = z || 0;
  1997  		this._w = ( w !== undefined ) ? w : 1;
  1998  
  1999  	}
  2000  
  2001  	Quaternion.prototype = {
  2002  
  2003  		constructor: Quaternion,
  2004  
  2005  		get x () {
  2006  
  2007  			return this._x;
  2008  
  2009  		},
  2010  
  2011  		set x ( value ) {
  2012  
  2013  			this._x = value;
  2014  			this.onChangeCallback();
  2015  
  2016  		},
  2017  
  2018  		get y () {
  2019  
  2020  			return this._y;
  2021  
  2022  		},
  2023  
  2024  		set y ( value ) {
  2025  
  2026  			this._y = value;
  2027  			this.onChangeCallback();
  2028  
  2029  		},
  2030  
  2031  		get z () {
  2032  
  2033  			return this._z;
  2034  
  2035  		},
  2036  
  2037  		set z ( value ) {
  2038  
  2039  			this._z = value;
  2040  			this.onChangeCallback();
  2041  
  2042  		},
  2043  
  2044  		get w () {
  2045  
  2046  			return this._w;
  2047  
  2048  		},
  2049  
  2050  		set w ( value ) {
  2051  
  2052  			this._w = value;
  2053  			this.onChangeCallback();
  2054  
  2055  		},
  2056  
  2057  		set: function ( x, y, z, w ) {
  2058  
  2059  			this._x = x;
  2060  			this._y = y;
  2061  			this._z = z;
  2062  			this._w = w;
  2063  
  2064  			this.onChangeCallback();
  2065  
  2066  			return this;
  2067  
  2068  		},
  2069  
  2070  		clone: function () {
  2071  
  2072  			return new this.constructor( this._x, this._y, this._z, this._w );
  2073  
  2074  		},
  2075  
  2076  		copy: function ( quaternion ) {
  2077  
  2078  			this._x = quaternion.x;
  2079  			this._y = quaternion.y;
  2080  			this._z = quaternion.z;
  2081  			this._w = quaternion.w;
  2082  
  2083  			this.onChangeCallback();
  2084  
  2085  			return this;
  2086  
  2087  		},
  2088  
  2089  		setFromEuler: function ( euler, update ) {
  2090  
  2091  			if ( (euler && euler.isEuler) === false ) {
  2092  
  2093  				throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
  2094  
  2095  			}
  2096  
  2097  			// http://www.mathworks.com/matlabcentral/fileexchange/
  2098  			// 	20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
  2099  			//	content/SpinCalc.m
  2100  
  2101  			var c1 = Math.cos( euler._x / 2 );
  2102  			var c2 = Math.cos( euler._y / 2 );
  2103  			var c3 = Math.cos( euler._z / 2 );
  2104  			var s1 = Math.sin( euler._x / 2 );
  2105  			var s2 = Math.sin( euler._y / 2 );
  2106  			var s3 = Math.sin( euler._z / 2 );
  2107  
  2108  			var order = euler.order;
  2109  
  2110  			if ( order === 'XYZ' ) {
  2111  
  2112  				this._x = s1 * c2 * c3 + c1 * s2 * s3;
  2113  				this._y = c1 * s2 * c3 - s1 * c2 * s3;
  2114  				this._z = c1 * c2 * s3 + s1 * s2 * c3;
  2115  				this._w = c1 * c2 * c3 - s1 * s2 * s3;
  2116  
  2117  			} else if ( order === 'YXZ' ) {
  2118  
  2119  				this._x = s1 * c2 * c3 + c1 * s2 * s3;
  2120  				this._y = c1 * s2 * c3 - s1 * c2 * s3;
  2121  				this._z = c1 * c2 * s3 - s1 * s2 * c3;
  2122  				this._w = c1 * c2 * c3 + s1 * s2 * s3;
  2123  
  2124  			} else if ( order === 'ZXY' ) {
  2125  
  2126  				this._x = s1 * c2 * c3 - c1 * s2 * s3;
  2127  				this._y = c1 * s2 * c3 + s1 * c2 * s3;
  2128  				this._z = c1 * c2 * s3 + s1 * s2 * c3;
  2129  				this._w = c1 * c2 * c3 - s1 * s2 * s3;
  2130  
  2131  			} else if ( order === 'ZYX' ) {
  2132  
  2133  				this._x = s1 * c2 * c3 - c1 * s2 * s3;
  2134  				this._y = c1 * s2 * c3 + s1 * c2 * s3;
  2135  				this._z = c1 * c2 * s3 - s1 * s2 * c3;
  2136  				this._w = c1 * c2 * c3 + s1 * s2 * s3;
  2137  
  2138  			} else if ( order === 'YZX' ) {
  2139  
  2140  				this._x = s1 * c2 * c3 + c1 * s2 * s3;
  2141  				this._y = c1 * s2 * c3 + s1 * c2 * s3;
  2142  				this._z = c1 * c2 * s3 - s1 * s2 * c3;
  2143  				this._w = c1 * c2 * c3 - s1 * s2 * s3;
  2144  
  2145  			} else if ( order === 'XZY' ) {
  2146  
  2147  				this._x = s1 * c2 * c3 - c1 * s2 * s3;
  2148  				this._y = c1 * s2 * c3 - s1 * c2 * s3;
  2149  				this._z = c1 * c2 * s3 + s1 * s2 * c3;
  2150  				this._w = c1 * c2 * c3 + s1 * s2 * s3;
  2151  
  2152  			}
  2153  
  2154  			if ( update !== false ) this.onChangeCallback();
  2155  
  2156  			return this;
  2157  
  2158  		},
  2159  
  2160  		setFromAxisAngle: function ( axis, angle ) {
  2161  
  2162  			// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
  2163  
  2164  			// assumes axis is normalized
  2165  
  2166  			var halfAngle = angle / 2, s = Math.sin( halfAngle );
  2167  
  2168  			this._x = axis.x * s;
  2169  			this._y = axis.y * s;
  2170  			this._z = axis.z * s;
  2171  			this._w = Math.cos( halfAngle );
  2172  
  2173  			this.onChangeCallback();
  2174  
  2175  			return this;
  2176  
  2177  		},
  2178  
  2179  		setFromRotationMatrix: function ( m ) {
  2180  
  2181  			// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
  2182  
  2183  			// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  2184  
  2185  			var te = m.elements,
  2186  
  2187  				m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
  2188  				m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
  2189  				m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
  2190  
  2191  				trace = m11 + m22 + m33,
  2192  				s;
  2193  
  2194  			if ( trace > 0 ) {
  2195  
  2196  				s = 0.5 / Math.sqrt( trace + 1.0 );
  2197  
  2198  				this._w = 0.25 / s;
  2199  				this._x = ( m32 - m23 ) * s;
  2200  				this._y = ( m13 - m31 ) * s;
  2201  				this._z = ( m21 - m12 ) * s;
  2202  
  2203  			} else if ( m11 > m22 && m11 > m33 ) {
  2204  
  2205  				s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
  2206  
  2207  				this._w = ( m32 - m23 ) / s;
  2208  				this._x = 0.25 * s;
  2209  				this._y = ( m12 + m21 ) / s;
  2210  				this._z = ( m13 + m31 ) / s;
  2211  
  2212  			} else if ( m22 > m33 ) {
  2213  
  2214  				s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
  2215  
  2216  				this._w = ( m13 - m31 ) / s;
  2217  				this._x = ( m12 + m21 ) / s;
  2218  				this._y = 0.25 * s;
  2219  				this._z = ( m23 + m32 ) / s;
  2220  
  2221  			} else {
  2222  
  2223  				s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
  2224  
  2225  				this._w = ( m21 - m12 ) / s;
  2226  				this._x = ( m13 + m31 ) / s;
  2227  				this._y = ( m23 + m32 ) / s;
  2228  				this._z = 0.25 * s;
  2229  
  2230  			}
  2231  
  2232  			this.onChangeCallback();
  2233  
  2234  			return this;
  2235  
  2236  		},
  2237  
  2238  		setFromUnitVectors: function () {
  2239  
  2240  			// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
  2241  
  2242  			// assumes direction vectors vFrom and vTo are normalized
  2243  
  2244  			var v1, r;
  2245  
  2246  			var EPS = 0.000001;
  2247  
  2248  			return function setFromUnitVectors( vFrom, vTo ) {
  2249  
  2250  				if ( v1 === undefined ) v1 = new Vector3();
  2251  
  2252  				r = vFrom.dot( vTo ) + 1;
  2253  
  2254  				if ( r < EPS ) {
  2255  
  2256  					r = 0;
  2257  
  2258  					if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
  2259  
  2260  						v1.set( - vFrom.y, vFrom.x, 0 );
  2261  
  2262  					} else {
  2263  
  2264  						v1.set( 0, - vFrom.z, vFrom.y );
  2265  
  2266  					}
  2267  
  2268  				} else {
  2269  
  2270  					v1.crossVectors( vFrom, vTo );
  2271  
  2272  				}
  2273  
  2274  				this._x = v1.x;
  2275  				this._y = v1.y;
  2276  				this._z = v1.z;
  2277  				this._w = r;
  2278  
  2279  				return this.normalize();
  2280  
  2281  			};
  2282  
  2283  		}(),
  2284  
  2285  		inverse: function () {
  2286  
  2287  			return this.conjugate().normalize();
  2288  
  2289  		},
  2290  
  2291  		conjugate: function () {
  2292  
  2293  			this._x *= - 1;
  2294  			this._y *= - 1;
  2295  			this._z *= - 1;
  2296  
  2297  			this.onChangeCallback();
  2298  
  2299  			return this;
  2300  
  2301  		},
  2302  
  2303  		dot: function ( v ) {
  2304  
  2305  			return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
  2306  
  2307  		},
  2308  
  2309  		lengthSq: function () {
  2310  
  2311  			return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
  2312  
  2313  		},
  2314  
  2315  		length: function () {
  2316  
  2317  			return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
  2318  
  2319  		},
  2320  
  2321  		normalize: function () {
  2322  
  2323  			var l = this.length();
  2324  
  2325  			if ( l === 0 ) {
  2326  
  2327  				this._x = 0;
  2328  				this._y = 0;
  2329  				this._z = 0;
  2330  				this._w = 1;
  2331  
  2332  			} else {
  2333  
  2334  				l = 1 / l;
  2335  
  2336  				this._x = this._x * l;
  2337  				this._y = this._y * l;
  2338  				this._z = this._z * l;
  2339  				this._w = this._w * l;
  2340  
  2341  			}
  2342  
  2343  			this.onChangeCallback();
  2344  
  2345  			return this;
  2346  
  2347  		},
  2348  
  2349  		multiply: function ( q, p ) {
  2350  
  2351  			if ( p !== undefined ) {
  2352  
  2353  				console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
  2354  				return this.multiplyQuaternions( q, p );
  2355  
  2356  			}
  2357  
  2358  			return this.multiplyQuaternions( this, q );
  2359  
  2360  		},
  2361  
  2362  		premultiply: function ( q ) {
  2363  
  2364  			return this.multiplyQuaternions( q, this );
  2365  
  2366  		},
  2367  
  2368  		multiplyQuaternions: function ( a, b ) {
  2369  
  2370  			// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
  2371  
  2372  			var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
  2373  			var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
  2374  
  2375  			this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
  2376  			this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
  2377  			this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
  2378  			this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
  2379  
  2380  			this.onChangeCallback();
  2381  
  2382  			return this;
  2383  
  2384  		},
  2385  
  2386  		slerp: function ( qb, t ) {
  2387  
  2388  			if ( t === 0 ) return this;
  2389  			if ( t === 1 ) return this.copy( qb );
  2390  
  2391  			var x = this._x, y = this._y, z = this._z, w = this._w;
  2392  
  2393  			// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
  2394  
  2395  			var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
  2396  
  2397  			if ( cosHalfTheta < 0 ) {
  2398  
  2399  				this._w = - qb._w;
  2400  				this._x = - qb._x;
  2401  				this._y = - qb._y;
  2402  				this._z = - qb._z;
  2403  
  2404  				cosHalfTheta = - cosHalfTheta;
  2405  
  2406  			} else {
  2407  
  2408  				this.copy( qb );
  2409  
  2410  			}
  2411  
  2412  			if ( cosHalfTheta >= 1.0 ) {
  2413  
  2414  				this._w = w;
  2415  				this._x = x;
  2416  				this._y = y;
  2417  				this._z = z;
  2418  
  2419  				return this;
  2420  
  2421  			}
  2422  
  2423  			var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
  2424  
  2425  			if ( Math.abs( sinHalfTheta ) < 0.001 ) {
  2426  
  2427  				this._w = 0.5 * ( w + this._w );
  2428  				this._x = 0.5 * ( x + this._x );
  2429  				this._y = 0.5 * ( y + this._y );
  2430  				this._z = 0.5 * ( z + this._z );
  2431  
  2432  				return this;
  2433  
  2434  			}
  2435  
  2436  			var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
  2437  			var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
  2438  			ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
  2439  
  2440  			this._w = ( w * ratioA + this._w * ratioB );
  2441  			this._x = ( x * ratioA + this._x * ratioB );
  2442  			this._y = ( y * ratioA + this._y * ratioB );
  2443  			this._z = ( z * ratioA + this._z * ratioB );
  2444  
  2445  			this.onChangeCallback();
  2446  
  2447  			return this;
  2448  
  2449  		},
  2450  
  2451  		equals: function ( quaternion ) {
  2452  
  2453  			return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
  2454  
  2455  		},
  2456  
  2457  		fromArray: function ( array, offset ) {
  2458  
  2459  			if ( offset === undefined ) offset = 0;
  2460  
  2461  			this._x = array[ offset ];
  2462  			this._y = array[ offset + 1 ];
  2463  			this._z = array[ offset + 2 ];
  2464  			this._w = array[ offset + 3 ];
  2465  
  2466  			this.onChangeCallback();
  2467  
  2468  			return this;
  2469  
  2470  		},
  2471  
  2472  		toArray: function ( array, offset ) {
  2473  
  2474  			if ( array === undefined ) array = [];
  2475  			if ( offset === undefined ) offset = 0;
  2476  
  2477  			array[ offset ] = this._x;
  2478  			array[ offset + 1 ] = this._y;
  2479  			array[ offset + 2 ] = this._z;
  2480  			array[ offset + 3 ] = this._w;
  2481  
  2482  			return array;
  2483  
  2484  		},
  2485  
  2486  		onChange: function ( callback ) {
  2487  
  2488  			this.onChangeCallback = callback;
  2489  
  2490  			return this;
  2491  
  2492  		},
  2493  
  2494  		onChangeCallback: function () {}
  2495  
  2496  	};
  2497  
  2498  	Object.assign( Quaternion, {
  2499  
  2500  		slerp: function( qa, qb, qm, t ) {
  2501  
  2502  			return qm.copy( qa ).slerp( qb, t );
  2503  
  2504  		},
  2505  
  2506  		slerpFlat: function(
  2507  				dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
  2508  
  2509  			// fuzz-free, array-based Quaternion SLERP operation
  2510  
  2511  			var x0 = src0[ srcOffset0 + 0 ],
  2512  				y0 = src0[ srcOffset0 + 1 ],
  2513  				z0 = src0[ srcOffset0 + 2 ],
  2514  				w0 = src0[ srcOffset0 + 3 ],
  2515  
  2516  				x1 = src1[ srcOffset1 + 0 ],
  2517  				y1 = src1[ srcOffset1 + 1 ],
  2518  				z1 = src1[ srcOffset1 + 2 ],
  2519  				w1 = src1[ srcOffset1 + 3 ];
  2520  
  2521  			if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
  2522  
  2523  				var s = 1 - t,
  2524  
  2525  					cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
  2526  
  2527  					dir = ( cos >= 0 ? 1 : - 1 ),
  2528  					sqrSin = 1 - cos * cos;
  2529  
  2530  				// Skip the Slerp for tiny steps to avoid numeric problems:
  2531  				if ( sqrSin > Number.EPSILON ) {
  2532  
  2533  					var sin = Math.sqrt( sqrSin ),
  2534  						len = Math.atan2( sin, cos * dir );
  2535  
  2536  					s = Math.sin( s * len ) / sin;
  2537  					t = Math.sin( t * len ) / sin;
  2538  
  2539  				}
  2540  
  2541  				var tDir = t * dir;
  2542  
  2543  				x0 = x0 * s + x1 * tDir;
  2544  				y0 = y0 * s + y1 * tDir;
  2545  				z0 = z0 * s + z1 * tDir;
  2546  				w0 = w0 * s + w1 * tDir;
  2547  
  2548  				// Normalize in case we just did a lerp:
  2549  				if ( s === 1 - t ) {
  2550  
  2551  					var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
  2552  
  2553  					x0 *= f;
  2554  					y0 *= f;
  2555  					z0 *= f;
  2556  					w0 *= f;
  2557  
  2558  				}
  2559  
  2560  			}
  2561  
  2562  			dst[ dstOffset ] = x0;
  2563  			dst[ dstOffset + 1 ] = y0;
  2564  			dst[ dstOffset + 2 ] = z0;
  2565  			dst[ dstOffset + 3 ] = w0;
  2566  
  2567  		}
  2568  
  2569  	} );
  2570  
  2571  	/**
  2572  	 * @author mrdoob / http://mrdoob.com/
  2573  	 * @author *kile / http://kile.stravaganza.org/
  2574  	 * @author philogb / http://blog.thejit.org/
  2575  	 * @author mikael emtinger / http://gomo.se/
  2576  	 * @author egraether / http://egraether.com/
  2577  	 * @author WestLangley / http://github.com/WestLangley
  2578  	 */
  2579  
  2580  	function Vector3( x, y, z ) {
  2581  
  2582  		this.x = x || 0;
  2583  		this.y = y || 0;
  2584  		this.z = z || 0;
  2585  
  2586  	}
  2587  
  2588  	Vector3.prototype = {
  2589  
  2590  		constructor: Vector3,
  2591  
  2592  		isVector3: true,
  2593  
  2594  		set: function ( x, y, z ) {
  2595  
  2596  			this.x = x;
  2597  			this.y = y;
  2598  			this.z = z;
  2599  
  2600  			return this;
  2601  
  2602  		},
  2603  
  2604  		setScalar: function ( scalar ) {
  2605  
  2606  			this.x = scalar;
  2607  			this.y = scalar;
  2608  			this.z = scalar;
  2609  
  2610  			return this;
  2611  
  2612  		},
  2613  
  2614  		setX: function ( x ) {
  2615  
  2616  			this.x = x;
  2617  
  2618  			return this;
  2619  
  2620  		},
  2621  
  2622  		setY: function ( y ) {
  2623  
  2624  			this.y = y;
  2625  
  2626  			return this;
  2627  
  2628  		},
  2629  
  2630  		setZ: function ( z ) {
  2631  
  2632  			this.z = z;
  2633  
  2634  			return this;
  2635  
  2636  		},
  2637  
  2638  		setComponent: function ( index, value ) {
  2639  
  2640  			switch ( index ) {
  2641  
  2642  				case 0: this.x = value; break;
  2643  				case 1: this.y = value; break;
  2644  				case 2: this.z = value; break;
  2645  				default: throw new Error( 'index is out of range: ' + index );
  2646  
  2647  			}
  2648  
  2649  			return this;
  2650  
  2651  		},
  2652  
  2653  		getComponent: function ( index ) {
  2654  
  2655  			switch ( index ) {
  2656  
  2657  				case 0: return this.x;
  2658  				case 1: return this.y;
  2659  				case 2: return this.z;
  2660  				default: throw new Error( 'index is out of range: ' + index );
  2661  
  2662  			}
  2663  
  2664  		},
  2665  
  2666  		clone: function () {
  2667  
  2668  			return new this.constructor( this.x, this.y, this.z );
  2669  
  2670  		},
  2671  
  2672  		copy: function ( v ) {
  2673  
  2674  			this.x = v.x;
  2675  			this.y = v.y;
  2676  			this.z = v.z;
  2677  
  2678  			return this;
  2679  
  2680  		},
  2681  
  2682  		add: function ( v, w ) {
  2683  
  2684  			if ( w !== undefined ) {
  2685  
  2686  				console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
  2687  				return this.addVectors( v, w );
  2688  
  2689  			}
  2690  
  2691  			this.x += v.x;
  2692  			this.y += v.y;
  2693  			this.z += v.z;
  2694  
  2695  			return this;
  2696  
  2697  		},
  2698  
  2699  		addScalar: function ( s ) {
  2700  
  2701  			this.x += s;
  2702  			this.y += s;
  2703  			this.z += s;
  2704  
  2705  			return this;
  2706  
  2707  		},
  2708  
  2709  		addVectors: function ( a, b ) {
  2710  
  2711  			this.x = a.x + b.x;
  2712  			this.y = a.y + b.y;
  2713  			this.z = a.z + b.z;
  2714  
  2715  			return this;
  2716  
  2717  		},
  2718  
  2719  		addScaledVector: function ( v, s ) {
  2720  
  2721  			this.x += v.x * s;
  2722  			this.y += v.y * s;
  2723  			this.z += v.z * s;
  2724  
  2725  			return this;
  2726  
  2727  		},
  2728  
  2729  		sub: function ( v, w ) {
  2730  
  2731  			if ( w !== undefined ) {
  2732  
  2733  				console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
  2734  				return this.subVectors( v, w );
  2735  
  2736  			}
  2737  
  2738  			this.x -= v.x;
  2739  			this.y -= v.y;
  2740  			this.z -= v.z;
  2741  
  2742  			return this;
  2743  
  2744  		},
  2745  
  2746  		subScalar: function ( s ) {
  2747  
  2748  			this.x -= s;
  2749  			this.y -= s;
  2750  			this.z -= s;
  2751  
  2752  			return this;
  2753  
  2754  		},
  2755  
  2756  		subVectors: function ( a, b ) {
  2757  
  2758  			this.x = a.x - b.x;
  2759  			this.y = a.y - b.y;
  2760  			this.z = a.z - b.z;
  2761  
  2762  			return this;
  2763  
  2764  		},
  2765  
  2766  		multiply: function ( v, w ) {
  2767  
  2768  			if ( w !== undefined ) {
  2769  
  2770  				console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
  2771  				return this.multiplyVectors( v, w );
  2772  
  2773  			}
  2774  
  2775  			this.x *= v.x;
  2776  			this.y *= v.y;
  2777  			this.z *= v.z;
  2778  
  2779  			return this;
  2780  
  2781  		},
  2782  
  2783  		multiplyScalar: function ( scalar ) {
  2784  
  2785  			if ( isFinite( scalar ) ) {
  2786  
  2787  				this.x *= scalar;
  2788  				this.y *= scalar;
  2789  				this.z *= scalar;
  2790  
  2791  			} else {
  2792  
  2793  				this.x = 0;
  2794  				this.y = 0;
  2795  				this.z = 0;
  2796  
  2797  			}
  2798  
  2799  			return this;
  2800  
  2801  		},
  2802  
  2803  		multiplyVectors: function ( a, b ) {
  2804  
  2805  			this.x = a.x * b.x;
  2806  			this.y = a.y * b.y;
  2807  			this.z = a.z * b.z;
  2808  
  2809  			return this;
  2810  
  2811  		},
  2812  
  2813  		applyEuler: function () {
  2814  
  2815  			var quaternion;
  2816  
  2817  			return function applyEuler( euler ) {
  2818  
  2819  				if ( (euler && euler.isEuler) === false ) {
  2820  
  2821  					console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );
  2822  
  2823  				}
  2824  
  2825  				if ( quaternion === undefined ) quaternion = new Quaternion();
  2826  
  2827  				return this.applyQuaternion( quaternion.setFromEuler( euler ) );
  2828  
  2829  			};
  2830  
  2831  		}(),
  2832  
  2833  		applyAxisAngle: function () {
  2834  
  2835  			var quaternion;
  2836  
  2837  			return function applyAxisAngle( axis, angle ) {
  2838  
  2839  				if ( quaternion === undefined ) quaternion = new Quaternion();
  2840  
  2841  				return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );
  2842  
  2843  			};
  2844  
  2845  		}(),
  2846  
  2847  		applyMatrix3: function ( m ) {
  2848  
  2849  			var x = this.x, y = this.y, z = this.z;
  2850  			var e = m.elements;
  2851  
  2852  			this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
  2853  			this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
  2854  			this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
  2855  
  2856  			return this;
  2857  
  2858  		},
  2859  
  2860  		applyMatrix4: function ( m ) {
  2861  
  2862  			var x = this.x, y = this.y, z = this.z;
  2863  			var e = m.elements;
  2864  
  2865  			this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z + e[ 12 ];
  2866  			this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z + e[ 13 ];
  2867  			this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ];
  2868  			var w =  e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ];
  2869  
  2870  			return this.divideScalar( w );
  2871  
  2872  		},
  2873  
  2874  		applyQuaternion: function ( q ) {
  2875  
  2876  			var x = this.x, y = this.y, z = this.z;
  2877  			var qx = q.x, qy = q.y, qz = q.z, qw = q.w;
  2878  
  2879  			// calculate quat * vector
  2880  
  2881  			var ix =  qw * x + qy * z - qz * y;
  2882  			var iy =  qw * y + qz * x - qx * z;
  2883  			var iz =  qw * z + qx * y - qy * x;
  2884  			var iw = - qx * x - qy * y - qz * z;
  2885  
  2886  			// calculate result * inverse quat
  2887  
  2888  			this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
  2889  			this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
  2890  			this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
  2891  
  2892  			return this;
  2893  
  2894  		},
  2895  
  2896  		project: function () {
  2897  
  2898  			var matrix;
  2899  
  2900  			return function project( camera ) {
  2901  
  2902  				if ( matrix === undefined ) matrix = new Matrix4();
  2903  
  2904  				matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
  2905  				return this.applyMatrix4( matrix );
  2906  
  2907  			};
  2908  
  2909  		}(),
  2910  
  2911  		unproject: function () {
  2912  
  2913  			var matrix;
  2914  
  2915  			return function unproject( camera ) {
  2916  
  2917  				if ( matrix === undefined ) matrix = new Matrix4();
  2918  
  2919  				matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
  2920  				return this.applyMatrix4( matrix );
  2921  
  2922  			};
  2923  
  2924  		}(),
  2925  
  2926  		transformDirection: function ( m ) {
  2927  
  2928  			// input: THREE.Matrix4 affine matrix
  2929  			// vector interpreted as a direction
  2930  
  2931  			var x = this.x, y = this.y, z = this.z;
  2932  			var e = m.elements;
  2933  
  2934  			this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z;
  2935  			this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z;
  2936  			this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
  2937  
  2938  			return this.normalize();
  2939  
  2940  		},
  2941  
  2942  		divide: function ( v ) {
  2943  
  2944  			this.x /= v.x;
  2945  			this.y /= v.y;
  2946  			this.z /= v.z;
  2947  
  2948  			return this;
  2949  
  2950  		},
  2951  
  2952  		divideScalar: function ( scalar ) {
  2953  
  2954  			return this.multiplyScalar( 1 / scalar );
  2955  
  2956  		},
  2957  
  2958  		min: function ( v ) {
  2959  
  2960  			this.x = Math.min( this.x, v.x );
  2961  			this.y = Math.min( this.y, v.y );
  2962  			this.z = Math.min( this.z, v.z );
  2963  
  2964  			return this;
  2965  
  2966  		},
  2967  
  2968  		max: function ( v ) {
  2969  
  2970  			this.x = Math.max( this.x, v.x );
  2971  			this.y = Math.max( this.y, v.y );
  2972  			this.z = Math.max( this.z, v.z );
  2973  
  2974  			return this;
  2975  
  2976  		},
  2977  
  2978  		clamp: function ( min, max ) {
  2979  
  2980  			// This function assumes min < max, if this assumption isn't true it will not operate correctly
  2981  
  2982  			this.x = Math.max( min.x, Math.min( max.x, this.x ) );
  2983  			this.y = Math.max( min.y, Math.min( max.y, this.y ) );
  2984  			this.z = Math.max( min.z, Math.min( max.z, this.z ) );
  2985  
  2986  			return this;
  2987  
  2988  		},
  2989  
  2990  		clampScalar: function () {
  2991  
  2992  			var min, max;
  2993  
  2994  			return function clampScalar( minVal, maxVal ) {
  2995  
  2996  				if ( min === undefined ) {
  2997  
  2998  					min = new Vector3();
  2999  					max = new Vector3();
  3000  
  3001  				}
  3002  
  3003  				min.set( minVal, minVal, minVal );
  3004  				max.set( maxVal, maxVal, maxVal );
  3005  
  3006  				return this.clamp( min, max );
  3007  
  3008  			};
  3009  
  3010  		}(),
  3011  
  3012  		clampLength: function ( min, max ) {
  3013  
  3014  			var length = this.length();
  3015  
  3016  			return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length );
  3017  
  3018  		},
  3019  
  3020  		floor: function () {
  3021  
  3022  			this.x = Math.floor( this.x );
  3023  			this.y = Math.floor( this.y );
  3024  			this.z = Math.floor( this.z );
  3025  
  3026  			return this;
  3027  
  3028  		},
  3029  
  3030  		ceil: function () {
  3031  
  3032  			this.x = Math.ceil( this.x );
  3033  			this.y = Math.ceil( this.y );
  3034  			this.z = Math.ceil( this.z );
  3035  
  3036  			return this;
  3037  
  3038  		},
  3039  
  3040  		round: function () {
  3041  
  3042  			this.x = Math.round( this.x );
  3043  			this.y = Math.round( this.y );
  3044  			this.z = Math.round( this.z );
  3045  
  3046  			return this;
  3047  
  3048  		},
  3049  
  3050  		roundToZero: function () {
  3051  
  3052  			this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
  3053  			this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
  3054  			this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
  3055  
  3056  			return this;
  3057  
  3058  		},
  3059  
  3060  		negate: function () {
  3061  
  3062  			this.x = - this.x;
  3063  			this.y = - this.y;
  3064  			this.z = - this.z;
  3065  
  3066  			return this;
  3067  
  3068  		},
  3069  
  3070  		dot: function ( v ) {
  3071  
  3072  			return this.x * v.x + this.y * v.y + this.z * v.z;
  3073  
  3074  		},
  3075  
  3076  		lengthSq: function () {
  3077  
  3078  			return this.x * this.x + this.y * this.y + this.z * this.z;
  3079  
  3080  		},
  3081  
  3082  		length: function () {
  3083  
  3084  			return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
  3085  
  3086  		},
  3087  
  3088  		lengthManhattan: function () {
  3089  
  3090  			return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
  3091  
  3092  		},
  3093  
  3094  		normalize: function () {
  3095  
  3096  			return this.divideScalar( this.length() );
  3097  
  3098  		},
  3099  
  3100  		setLength: function ( length ) {
  3101  
  3102  			return this.multiplyScalar( length / this.length() );
  3103  
  3104  		},
  3105  
  3106  		lerp: function ( v, alpha ) {
  3107  
  3108  			this.x += ( v.x - this.x ) * alpha;
  3109  			this.y += ( v.y - this.y ) * alpha;
  3110  			this.z += ( v.z - this.z ) * alpha;
  3111  
  3112  			return this;
  3113  
  3114  		},
  3115  
  3116  		lerpVectors: function ( v1, v2, alpha ) {
  3117  
  3118  			return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
  3119  
  3120  		},
  3121  
  3122  		cross: function ( v, w ) {
  3123  
  3124  			if ( w !== undefined ) {
  3125  
  3126  				console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
  3127  				return this.crossVectors( v, w );
  3128  
  3129  			}
  3130  
  3131  			var x = this.x, y = this.y, z = this.z;
  3132  
  3133  			this.x = y * v.z - z * v.y;
  3134  			this.y = z * v.x - x * v.z;
  3135  			this.z = x * v.y - y * v.x;
  3136  
  3137  			return this;
  3138  
  3139  		},
  3140  
  3141  		crossVectors: function ( a, b ) {
  3142  
  3143  			var ax = a.x, ay = a.y, az = a.z;
  3144  			var bx = b.x, by = b.y, bz = b.z;
  3145  
  3146  			this.x = ay * bz - az * by;
  3147  			this.y = az * bx - ax * bz;
  3148  			this.z = ax * by - ay * bx;
  3149  
  3150  			return this;
  3151  
  3152  		},
  3153  
  3154  		projectOnVector: function ( vector ) {
  3155  
  3156  			var scalar = vector.dot( this ) / vector.lengthSq();
  3157  
  3158  			return this.copy( vector ).multiplyScalar( scalar );
  3159  
  3160  		},
  3161  
  3162  		projectOnPlane: function () {
  3163  
  3164  			var v1;
  3165  
  3166  			return function projectOnPlane( planeNormal ) {
  3167  
  3168  				if ( v1 === undefined ) v1 = new Vector3();
  3169  
  3170  				v1.copy( this ).projectOnVector( planeNormal );
  3171  
  3172  				return this.sub( v1 );
  3173  
  3174  			};
  3175  
  3176  		}(),
  3177  
  3178  		reflect: function () {
  3179  
  3180  			// reflect incident vector off plane orthogonal to normal
  3181  			// normal is assumed to have unit length
  3182  
  3183  			var v1;
  3184  
  3185  			return function reflect( normal ) {
  3186  
  3187  				if ( v1 === undefined ) v1 = new Vector3();
  3188  
  3189  				return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
  3190  
  3191  			};
  3192  
  3193  		}(),
  3194  
  3195  		angleTo: function ( v ) {
  3196  
  3197  			var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) );
  3198  
  3199  			// clamp, to handle numerical problems
  3200  
  3201  			return Math.acos( _Math.clamp( theta, - 1, 1 ) );
  3202  
  3203  		},
  3204  
  3205  		distanceTo: function ( v ) {
  3206  
  3207  			return Math.sqrt( this.distanceToSquared( v ) );
  3208  
  3209  		},
  3210  
  3211  		distanceToSquared: function ( v ) {
  3212  
  3213  			var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
  3214  
  3215  			return dx * dx + dy * dy + dz * dz;
  3216  
  3217  		},
  3218  
  3219  		distanceToManhattan: function ( v ) {
  3220  
  3221  			return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
  3222  
  3223  		},
  3224  
  3225  		setFromSpherical: function( s ) {
  3226  
  3227  			var sinPhiRadius = Math.sin( s.phi ) * s.radius;
  3228  
  3229  			this.x = sinPhiRadius * Math.sin( s.theta );
  3230  			this.y = Math.cos( s.phi ) * s.radius;
  3231  			this.z = sinPhiRadius * Math.cos( s.theta );
  3232  
  3233  			return this;
  3234  
  3235  		},
  3236  
  3237  		setFromCylindrical: function( c ) {
  3238  
  3239  			this.x = c.radius * Math.sin( c.theta );
  3240  			this.y = c.y;
  3241  			this.z = c.radius * Math.cos( c.theta );
  3242  
  3243  			return this;
  3244  
  3245  		},
  3246  
  3247  		setFromMatrixPosition: function ( m ) {
  3248  
  3249  			return this.setFromMatrixColumn( m, 3 );
  3250  
  3251  		},
  3252  
  3253  		setFromMatrixScale: function ( m ) {
  3254  
  3255  			var sx = this.setFromMatrixColumn( m, 0 ).length();
  3256  			var sy = this.setFromMatrixColumn( m, 1 ).length();
  3257  			var sz = this.setFromMatrixColumn( m, 2 ).length();
  3258  
  3259  			this.x = sx;
  3260  			this.y = sy;
  3261  			this.z = sz;
  3262  
  3263  			return this;
  3264  
  3265  		},
  3266  
  3267  		setFromMatrixColumn: function ( m, index ) {
  3268  
  3269  			if ( typeof m === 'number' ) {
  3270  
  3271  				console.warn( 'THREE.Vector3: setFromMatrixColumn now expects ( matrix, index ).' );
  3272  				var temp = m;
  3273  				m = index;
  3274  				index = temp;
  3275  
  3276  			}
  3277  
  3278  			return this.fromArray( m.elements, index * 4 );
  3279  
  3280  		},
  3281  
  3282  		equals: function ( v ) {
  3283  
  3284  			return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
  3285  
  3286  		},
  3287  
  3288  		fromArray: function ( array, offset ) {
  3289  
  3290  			if ( offset === undefined ) offset = 0;
  3291  
  3292  			this.x = array[ offset ];
  3293  			this.y = array[ offset + 1 ];
  3294  			this.z = array[ offset + 2 ];
  3295  
  3296  			return this;
  3297  
  3298  		},
  3299  
  3300  		toArray: function ( array, offset ) {
  3301  
  3302  			if ( array === undefined ) array = [];
  3303  			if ( offset === undefined ) offset = 0;
  3304  
  3305  			array[ offset ] = this.x;
  3306  			array[ offset + 1 ] = this.y;
  3307  			array[ offset + 2 ] = this.z;
  3308  
  3309  			return array;
  3310  
  3311  		},
  3312  
  3313  		fromBufferAttribute: function ( attribute, index, offset ) {
  3314  
  3315  			if ( offset !== undefined ) {
  3316  
  3317  				console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );
  3318  
  3319  			}
  3320  
  3321  			this.x = attribute.getX( index );
  3322  			this.y = attribute.getY( index );
  3323  			this.z = attribute.getZ( index );
  3324  
  3325  			return this;
  3326  
  3327  		}
  3328  
  3329  	};
  3330  
  3331  	/**
  3332  	 * @author mrdoob / http://mrdoob.com/
  3333  	 * @author supereggbert / http://www.paulbrunt.co.uk/
  3334  	 * @author philogb / http://blog.thejit.org/
  3335  	 * @author jordi_ros / http://plattsoft.com
  3336  	 * @author D1plo1d / http://github.com/D1plo1d
  3337  	 * @author alteredq / http://alteredqualia.com/
  3338  	 * @author mikael emtinger / http://gomo.se/
  3339  	 * @author timknip / http://www.floorplanner.com/
  3340  	 * @author bhouston / http://clara.io
  3341  	 * @author WestLangley / http://github.com/WestLangley
  3342  	 */
  3343  
  3344  	function Matrix4() {
  3345  
  3346  		this.elements = new Float32Array( [
  3347  
  3348  			1, 0, 0, 0,
  3349  			0, 1, 0, 0,
  3350  			0, 0, 1, 0,
  3351  			0, 0, 0, 1
  3352  
  3353  		] );
  3354  
  3355  		if ( arguments.length > 0 ) {
  3356  
  3357  			console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );
  3358  
  3359  		}
  3360  
  3361  	}
  3362  
  3363  	Matrix4.prototype = {
  3364  
  3365  		constructor: Matrix4,
  3366  
  3367  		isMatrix4: true,
  3368  
  3369  		set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
  3370  
  3371  			var te = this.elements;
  3372  
  3373  			te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
  3374  			te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
  3375  			te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
  3376  			te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
  3377  
  3378  			return this;
  3379  
  3380  		},
  3381  
  3382  		identity: function () {
  3383  
  3384  			this.set(
  3385  
  3386  				1, 0, 0, 0,
  3387  				0, 1, 0, 0,
  3388  				0, 0, 1, 0,
  3389  				0, 0, 0, 1
  3390  
  3391  			);
  3392  
  3393  			return this;
  3394  
  3395  		},
  3396  
  3397  		clone: function () {
  3398  
  3399  			return new Matrix4().fromArray( this.elements );
  3400  
  3401  		},
  3402  
  3403  		copy: function ( m ) {
  3404  
  3405  			this.elements.set( m.elements );
  3406  
  3407  			return this;
  3408  
  3409  		},
  3410  
  3411  		copyPosition: function ( m ) {
  3412  
  3413  			var te = this.elements;
  3414  			var me = m.elements;
  3415  
  3416  			te[ 12 ] = me[ 12 ];
  3417  			te[ 13 ] = me[ 13 ];
  3418  			te[ 14 ] = me[ 14 ];
  3419  
  3420  			return this;
  3421  
  3422  		},
  3423  
  3424  		extractBasis: function ( xAxis, yAxis, zAxis ) {
  3425  
  3426  			xAxis.setFromMatrixColumn( this, 0 );
  3427  			yAxis.setFromMatrixColumn( this, 1 );
  3428  			zAxis.setFromMatrixColumn( this, 2 );
  3429  
  3430  			return this;
  3431  
  3432  		},
  3433  
  3434  		makeBasis: function ( xAxis, yAxis, zAxis ) {
  3435  
  3436  			this.set(
  3437  				xAxis.x, yAxis.x, zAxis.x, 0,
  3438  				xAxis.y, yAxis.y, zAxis.y, 0,
  3439  				xAxis.z, yAxis.z, zAxis.z, 0,
  3440  				0,       0,       0,       1
  3441  			);
  3442  
  3443  			return this;
  3444  
  3445  		},
  3446  
  3447  		extractRotation: function () {
  3448  
  3449  			var v1;
  3450  
  3451  			return function extractRotation( m ) {
  3452  
  3453  				if ( v1 === undefined ) v1 = new Vector3();
  3454  
  3455  				var te = this.elements;
  3456  				var me = m.elements;
  3457  
  3458  				var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length();
  3459  				var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length();
  3460  				var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length();
  3461  
  3462  				te[ 0 ] = me[ 0 ] * scaleX;
  3463  				te[ 1 ] = me[ 1 ] * scaleX;
  3464  				te[ 2 ] = me[ 2 ] * scaleX;
  3465  
  3466  				te[ 4 ] = me[ 4 ] * scaleY;
  3467  				te[ 5 ] = me[ 5 ] * scaleY;
  3468  				te[ 6 ] = me[ 6 ] * scaleY;
  3469  
  3470  				te[ 8 ] = me[ 8 ] * scaleZ;
  3471  				te[ 9 ] = me[ 9 ] * scaleZ;
  3472  				te[ 10 ] = me[ 10 ] * scaleZ;
  3473  
  3474  				return this;
  3475  
  3476  			};
  3477  
  3478  		}(),
  3479  
  3480  		makeRotationFromEuler: function ( euler ) {
  3481  
  3482  			if ( (euler && euler.isEuler) === false ) {
  3483  
  3484  				console.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
  3485  
  3486  			}
  3487  
  3488  			var te = this.elements;
  3489  
  3490  			var x = euler.x, y = euler.y, z = euler.z;
  3491  			var a = Math.cos( x ), b = Math.sin( x );
  3492  			var c = Math.cos( y ), d = Math.sin( y );
  3493  			var e = Math.cos( z ), f = Math.sin( z );
  3494  
  3495  			if ( euler.order === 'XYZ' ) {
  3496  
  3497  				var ae = a * e, af = a * f, be = b * e, bf = b * f;
  3498  
  3499  				te[ 0 ] = c * e;
  3500  				te[ 4 ] = - c * f;
  3501  				te[ 8 ] = d;
  3502  
  3503  				te[ 1 ] = af + be * d;
  3504  				te[ 5 ] = ae - bf * d;
  3505  				te[ 9 ] = - b * c;
  3506  
  3507  				te[ 2 ] = bf - ae * d;
  3508  				te[ 6 ] = be + af * d;
  3509  				te[ 10 ] = a * c;
  3510  
  3511  			} else if ( euler.order === 'YXZ' ) {
  3512  
  3513  				var ce = c * e, cf = c * f, de = d * e, df = d * f;
  3514  
  3515  				te[ 0 ] = ce + df * b;
  3516  				te[ 4 ] = de * b - cf;
  3517  				te[ 8 ] = a * d;
  3518  
  3519  				te[ 1 ] = a * f;
  3520  				te[ 5 ] = a * e;
  3521  				te[ 9 ] = - b;
  3522  
  3523  				te[ 2 ] = cf * b - de;
  3524  				te[ 6 ] = df + ce * b;
  3525  				te[ 10 ] = a * c;
  3526  
  3527  			} else if ( euler.order === 'ZXY' ) {
  3528  
  3529  				var ce = c * e, cf = c * f, de = d * e, df = d * f;
  3530  
  3531  				te[ 0 ] = ce - df * b;
  3532  				te[ 4 ] = - a * f;
  3533  				te[ 8 ] = de + cf * b;
  3534  
  3535  				te[ 1 ] = cf + de * b;
  3536  				te[ 5 ] = a * e;
  3537  				te[ 9 ] = df - ce * b;
  3538  
  3539  				te[ 2 ] = - a * d;
  3540  				te[ 6 ] = b;
  3541  				te[ 10 ] = a * c;
  3542  
  3543  			} else if ( euler.order === 'ZYX' ) {
  3544  
  3545  				var ae = a * e, af = a * f, be = b * e, bf = b * f;
  3546  
  3547  				te[ 0 ] = c * e;
  3548  				te[ 4 ] = be * d - af;
  3549  				te[ 8 ] = ae * d + bf;
  3550  
  3551  				te[ 1 ] = c * f;
  3552  				te[ 5 ] = bf * d + ae;
  3553  				te[ 9 ] = af * d - be;
  3554  
  3555  				te[ 2 ] = - d;
  3556  				te[ 6 ] = b * c;
  3557  				te[ 10 ] = a * c;
  3558  
  3559  			} else if ( euler.order === 'YZX' ) {
  3560  
  3561  				var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
  3562  
  3563  				te[ 0 ] = c * e;
  3564  				te[ 4 ] = bd - ac * f;
  3565  				te[ 8 ] = bc * f + ad;
  3566  
  3567  				te[ 1 ] = f;
  3568  				te[ 5 ] = a * e;
  3569  				te[ 9 ] = - b * e;
  3570  
  3571  				te[ 2 ] = - d * e;
  3572  				te[ 6 ] = ad * f + bc;
  3573  				te[ 10 ] = ac - bd * f;
  3574  
  3575  			} else if ( euler.order === 'XZY' ) {
  3576  
  3577  				var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
  3578  
  3579  				te[ 0 ] = c * e;
  3580  				te[ 4 ] = - f;
  3581  				te[ 8 ] = d * e;
  3582  
  3583  				te[ 1 ] = ac * f + bd;
  3584  				te[ 5 ] = a * e;
  3585  				te[ 9 ] = ad * f - bc;
  3586  
  3587  				te[ 2 ] = bc * f - ad;
  3588  				te[ 6 ] = b * e;
  3589  				te[ 10 ] = bd * f + ac;
  3590  
  3591  			}
  3592  
  3593  			// last column
  3594  			te[ 3 ] = 0;
  3595  			te[ 7 ] = 0;
  3596  			te[ 11 ] = 0;
  3597  
  3598  			// bottom row
  3599  			te[ 12 ] = 0;
  3600  			te[ 13 ] = 0;
  3601  			te[ 14 ] = 0;
  3602  			te[ 15 ] = 1;
  3603  
  3604  			return this;
  3605  
  3606  		},
  3607  
  3608  		makeRotationFromQuaternion: function ( q ) {
  3609  
  3610  			var te = this.elements;
  3611  
  3612  			var x = q.x, y = q.y, z = q.z, w = q.w;
  3613  			var x2 = x + x, y2 = y + y, z2 = z + z;
  3614  			var xx = x * x2, xy = x * y2, xz = x * z2;
  3615  			var yy = y * y2, yz = y * z2, zz = z * z2;
  3616  			var wx = w * x2, wy = w * y2, wz = w * z2;
  3617  
  3618  			te[ 0 ] = 1 - ( yy + zz );
  3619  			te[ 4 ] = xy - wz;
  3620  			te[ 8 ] = xz + wy;
  3621  
  3622  			te[ 1 ] = xy + wz;
  3623  			te[ 5 ] = 1 - ( xx + zz );
  3624  			te[ 9 ] = yz - wx;
  3625  
  3626  			te[ 2 ] = xz - wy;
  3627  			te[ 6 ] = yz + wx;
  3628  			te[ 10 ] = 1 - ( xx + yy );
  3629  
  3630  			// last column
  3631  			te[ 3 ] = 0;
  3632  			te[ 7 ] = 0;
  3633  			te[ 11 ] = 0;
  3634  
  3635  			// bottom row
  3636  			te[ 12 ] = 0;
  3637  			te[ 13 ] = 0;
  3638  			te[ 14 ] = 0;
  3639  			te[ 15 ] = 1;
  3640  
  3641  			return this;
  3642  
  3643  		},
  3644  
  3645  		lookAt: function () {
  3646  
  3647  			var x, y, z;
  3648  
  3649  			return function lookAt( eye, target, up ) {
  3650  
  3651  				if ( x === undefined ) {
  3652  
  3653  					x = new Vector3();
  3654  					y = new Vector3();
  3655  					z = new Vector3();
  3656  
  3657  				}
  3658  
  3659  				var te = this.elements;
  3660  
  3661  				z.subVectors( eye, target ).normalize();
  3662  
  3663  				if ( z.lengthSq() === 0 ) {
  3664  
  3665  					z.z = 1;
  3666  
  3667  				}
  3668  
  3669  				x.crossVectors( up, z ).normalize();
  3670  
  3671  				if ( x.lengthSq() === 0 ) {
  3672  
  3673  					z.z += 0.0001;
  3674  					x.crossVectors( up, z ).normalize();
  3675  
  3676  				}
  3677  
  3678  				y.crossVectors( z, x );
  3679  
  3680  
  3681  				te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
  3682  				te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
  3683  				te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;
  3684  
  3685  				return this;
  3686  
  3687  			};
  3688  
  3689  		}(),
  3690  
  3691  		multiply: function ( m, n ) {
  3692  
  3693  			if ( n !== undefined ) {
  3694  
  3695  				console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
  3696  				return this.multiplyMatrices( m, n );
  3697  
  3698  			}
  3699  
  3700  			return this.multiplyMatrices( this, m );
  3701  
  3702  		},
  3703  
  3704  		premultiply: function ( m ) {
  3705  
  3706  			return this.multiplyMatrices( m, this );
  3707  
  3708  		},
  3709  
  3710  		multiplyMatrices: function ( a, b ) {
  3711  
  3712  			var ae = a.elements;
  3713  			var be = b.elements;
  3714  			var te = this.elements;
  3715  
  3716  			var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
  3717  			var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
  3718  			var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
  3719  			var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
  3720  
  3721  			var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
  3722  			var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
  3723  			var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
  3724  			var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
  3725  
  3726  			te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
  3727  			te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
  3728  			te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
  3729  			te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
  3730  
  3731  			te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
  3732  			te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
  3733  			te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
  3734  			te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
  3735  
  3736  			te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
  3737  			te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
  3738  			te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
  3739  			te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
  3740  
  3741  			te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
  3742  			te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
  3743  			te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
  3744  			te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
  3745  
  3746  			return this;
  3747  
  3748  		},
  3749  
  3750  		multiplyToArray: function ( a, b, r ) {
  3751  
  3752  			var te = this.elements;
  3753  
  3754  			this.multiplyMatrices( a, b );
  3755  
  3756  			r[ 0 ] = te[ 0 ]; r[ 1 ] = te[ 1 ]; r[ 2 ] = te[ 2 ]; r[ 3 ] = te[ 3 ];
  3757  			r[ 4 ] = te[ 4 ]; r[ 5 ] = te[ 5 ]; r[ 6 ] = te[ 6 ]; r[ 7 ] = te[ 7 ];
  3758  			r[ 8 ]  = te[ 8 ]; r[ 9 ]  = te[ 9 ]; r[ 10 ] = te[ 10 ]; r[ 11 ] = te[ 11 ];
  3759  			r[ 12 ] = te[ 12 ]; r[ 13 ] = te[ 13 ]; r[ 14 ] = te[ 14 ]; r[ 15 ] = te[ 15 ];
  3760  
  3761  			return this;
  3762  
  3763  		},
  3764  
  3765  		multiplyScalar: function ( s ) {
  3766  
  3767  			var te = this.elements;
  3768  
  3769  			te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
  3770  			te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
  3771  			te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
  3772  			te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
  3773  
  3774  			return this;
  3775  
  3776  		},
  3777  
  3778  		applyToBufferAttribute: function () {
  3779  
  3780  			var v1;
  3781  
  3782  			return function applyToBufferAttribute( attribute ) {
  3783  
  3784  				if ( v1 === undefined ) v1 = new Vector3();
  3785  
  3786  				for ( var i = 0, l = attribute.count; i < l; i ++ ) {
  3787  
  3788  					v1.x = attribute.getX( i );
  3789  					v1.y = attribute.getY( i );
  3790  					v1.z = attribute.getZ( i );
  3791  
  3792  					v1.applyMatrix4( this );
  3793  
  3794  					attribute.setXYZ( i, v1.x, v1.y, v1.z );
  3795  
  3796  				}
  3797  
  3798  				return attribute;
  3799  
  3800  			};
  3801  
  3802  		}(),
  3803  
  3804  		determinant: function () {
  3805  
  3806  			var te = this.elements;
  3807  
  3808  			var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
  3809  			var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
  3810  			var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
  3811  			var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
  3812  
  3813  			//TODO: make this more efficient
  3814  			//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
  3815  
  3816  			return (
  3817  				n41 * (
  3818  					+ n14 * n23 * n32
  3819  					 - n13 * n24 * n32
  3820  					 - n14 * n22 * n33
  3821  					 + n12 * n24 * n33
  3822  					 + n13 * n22 * n34
  3823  					 - n12 * n23 * n34
  3824  				) +
  3825  				n42 * (
  3826  					+ n11 * n23 * n34
  3827  					 - n11 * n24 * n33
  3828  					 + n14 * n21 * n33
  3829  					 - n13 * n21 * n34
  3830  					 + n13 * n24 * n31
  3831  					 - n14 * n23 * n31
  3832  				) +
  3833  				n43 * (
  3834  					+ n11 * n24 * n32
  3835  					 - n11 * n22 * n34
  3836  					 - n14 * n21 * n32
  3837  					 + n12 * n21 * n34
  3838  					 + n14 * n22 * n31
  3839  					 - n12 * n24 * n31
  3840  				) +
  3841  				n44 * (
  3842  					- n13 * n22 * n31
  3843  					 - n11 * n23 * n32
  3844  					 + n11 * n22 * n33
  3845  					 + n13 * n21 * n32
  3846  					 - n12 * n21 * n33
  3847  					 + n12 * n23 * n31
  3848  				)
  3849  
  3850  			);
  3851  
  3852  		},
  3853  
  3854  		transpose: function () {
  3855  
  3856  			var te = this.elements;
  3857  			var tmp;
  3858  
  3859  			tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
  3860  			tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
  3861  			tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
  3862  
  3863  			tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
  3864  			tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
  3865  			tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
  3866  
  3867  			return this;
  3868  
  3869  		},
  3870  
  3871  		setPosition: function ( v ) {
  3872  
  3873  			var te = this.elements;
  3874  
  3875  			te[ 12 ] = v.x;
  3876  			te[ 13 ] = v.y;
  3877  			te[ 14 ] = v.z;
  3878  
  3879  			return this;
  3880  
  3881  		},
  3882  
  3883  		getInverse: function ( m, throwOnDegenerate ) {
  3884  
  3885  			// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
  3886  			var te = this.elements,
  3887  				me = m.elements,
  3888  
  3889  				n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ],
  3890  				n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ],
  3891  				n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ],
  3892  				n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ],
  3893  
  3894  				t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
  3895  				t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
  3896  				t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
  3897  				t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
  3898  
  3899  			var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
  3900  
  3901  			if ( det === 0 ) {
  3902  
  3903  				var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0";
  3904  
  3905  				if ( throwOnDegenerate === true ) {
  3906  
  3907  					throw new Error( msg );
  3908  
  3909  				} else {
  3910  
  3911  					console.warn( msg );
  3912  
  3913  				}
  3914  
  3915  				return this.identity();
  3916  
  3917  			}
  3918  
  3919  			var detInv = 1 / det;
  3920  
  3921  			te[ 0 ] = t11 * detInv;
  3922  			te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
  3923  			te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
  3924  			te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
  3925  
  3926  			te[ 4 ] = t12 * detInv;
  3927  			te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
  3928  			te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
  3929  			te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
  3930  
  3931  			te[ 8 ] = t13 * detInv;
  3932  			te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
  3933  			te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
  3934  			te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
  3935  
  3936  			te[ 12 ] = t14 * detInv;
  3937  			te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
  3938  			te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
  3939  			te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
  3940  
  3941  			return this;
  3942  
  3943  		},
  3944  
  3945  		scale: function ( v ) {
  3946  
  3947  			var te = this.elements;
  3948  			var x = v.x, y = v.y, z = v.z;
  3949  
  3950  			te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
  3951  			te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
  3952  			te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
  3953  			te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
  3954  
  3955  			return this;
  3956  
  3957  		},
  3958  
  3959  		getMaxScaleOnAxis: function () {
  3960  
  3961  			var te = this.elements;
  3962  
  3963  			var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
  3964  			var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
  3965  			var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
  3966  
  3967  			return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
  3968  
  3969  		},
  3970  
  3971  		makeTranslation: function ( x, y, z ) {
  3972  
  3973  			this.set(
  3974  
  3975  				1, 0, 0, x,
  3976  				0, 1, 0, y,
  3977  				0, 0, 1, z,
  3978  				0, 0, 0, 1
  3979  
  3980  			);
  3981  
  3982  			return this;
  3983  
  3984  		},
  3985  
  3986  		makeRotationX: function ( theta ) {
  3987  
  3988  			var c = Math.cos( theta ), s = Math.sin( theta );
  3989  
  3990  			this.set(
  3991  
  3992  				1, 0,  0, 0,
  3993  				0, c, - s, 0,
  3994  				0, s,  c, 0,
  3995  				0, 0,  0, 1
  3996  
  3997  			);
  3998  
  3999  			return this;
  4000  
  4001  		},
  4002  
  4003  		makeRotationY: function ( theta ) {
  4004  
  4005  			var c = Math.cos( theta ), s = Math.sin( theta );
  4006  
  4007  			this.set(
  4008  
  4009  				 c, 0, s, 0,
  4010  				 0, 1, 0, 0,
  4011  				- s, 0, c, 0,
  4012  				 0, 0, 0, 1
  4013  
  4014  			);
  4015  
  4016  			return this;
  4017  
  4018  		},
  4019  
  4020  		makeRotationZ: function ( theta ) {
  4021  
  4022  			var c = Math.cos( theta ), s = Math.sin( theta );
  4023  
  4024  			this.set(
  4025  
  4026  				c, - s, 0, 0,
  4027  				s,  c, 0, 0,
  4028  				0,  0, 1, 0,
  4029  				0,  0, 0, 1
  4030  
  4031  			);
  4032  
  4033  			return this;
  4034  
  4035  		},
  4036  
  4037  		makeRotationAxis: function ( axis, angle ) {
  4038  
  4039  			// Based on http://www.gamedev.net/reference/articles/article1199.asp
  4040  
  4041  			var c = Math.cos( angle );
  4042  			var s = Math.sin( angle );
  4043  			var t = 1 - c;
  4044  			var x = axis.x, y = axis.y, z = axis.z;
  4045  			var tx = t * x, ty = t * y;
  4046  
  4047  			this.set(
  4048  
  4049  				tx * x + c, tx * y - s * z, tx * z + s * y, 0,
  4050  				tx * y + s * z, ty * y + c, ty * z - s * x, 0,
  4051  				tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
  4052  				0, 0, 0, 1
  4053  
  4054  			);
  4055  
  4056  			 return this;
  4057  
  4058  		},
  4059  
  4060  		makeScale: function ( x, y, z ) {
  4061  
  4062  			this.set(
  4063  
  4064  				x, 0, 0, 0,
  4065  				0, y, 0, 0,
  4066  				0, 0, z, 0,
  4067  				0, 0, 0, 1
  4068  
  4069  			);
  4070  
  4071  			return this;
  4072  
  4073  		},
  4074  
  4075  		makeShear: function ( x, y, z ) {
  4076  
  4077  			this.set(
  4078  
  4079  				1, y, z, 0,
  4080  				x, 1, z, 0,
  4081  				x, y, 1, 0,
  4082  				0, 0, 0, 1
  4083  
  4084  			);
  4085  
  4086  			return this;
  4087  
  4088  		},
  4089  
  4090  		compose: function ( position, quaternion, scale ) {
  4091  
  4092  			this.makeRotationFromQuaternion( quaternion );
  4093  			this.scale( scale );
  4094  			this.setPosition( position );
  4095  
  4096  			return this;
  4097  
  4098  		},
  4099  
  4100  		decompose: function () {
  4101  
  4102  			var vector, matrix;
  4103  
  4104  			return function decompose( position, quaternion, scale ) {
  4105  
  4106  				if ( vector === undefined ) {
  4107  
  4108  					vector = new Vector3();
  4109  					matrix = new Matrix4();
  4110  
  4111  				}
  4112  
  4113  				var te = this.elements;
  4114  
  4115  				var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
  4116  				var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
  4117  				var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
  4118  
  4119  				// if determine is negative, we need to invert one scale
  4120  				var det = this.determinant();
  4121  				if ( det < 0 ) {
  4122  
  4123  					sx = - sx;
  4124  
  4125  				}
  4126  
  4127  				position.x = te[ 12 ];
  4128  				position.y = te[ 13 ];
  4129  				position.z = te[ 14 ];
  4130  
  4131  				// scale the rotation part
  4132  
  4133  				matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy()
  4134  
  4135  				var invSX = 1 / sx;
  4136  				var invSY = 1 / sy;
  4137  				var invSZ = 1 / sz;
  4138  
  4139  				matrix.elements[ 0 ] *= invSX;
  4140  				matrix.elements[ 1 ] *= invSX;
  4141  				matrix.elements[ 2 ] *= invSX;
  4142  
  4143  				matrix.elements[ 4 ] *= invSY;
  4144  				matrix.elements[ 5 ] *= invSY;
  4145  				matrix.elements[ 6 ] *= invSY;
  4146  
  4147  				matrix.elements[ 8 ] *= invSZ;
  4148  				matrix.elements[ 9 ] *= invSZ;
  4149  				matrix.elements[ 10 ] *= invSZ;
  4150  
  4151  				quaternion.setFromRotationMatrix( matrix );
  4152  
  4153  				scale.x = sx;
  4154  				scale.y = sy;
  4155  				scale.z = sz;
  4156  
  4157  				return this;
  4158  
  4159  			};
  4160  
  4161  		}(),
  4162  
  4163  		makePerspective: function ( left, right, top, bottom, near, far ) {
  4164  
  4165  			if ( far === undefined ) {
  4166  
  4167  				console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );
  4168  
  4169  			}
  4170  
  4171  			var te = this.elements;
  4172  			var x = 2 * near / ( right - left );
  4173  			var y = 2 * near / ( top - bottom );
  4174  
  4175  			var a = ( right + left ) / ( right - left );
  4176  			var b = ( top + bottom ) / ( top - bottom );
  4177  			var c = - ( far + near ) / ( far - near );
  4178  			var d = - 2 * far * near / ( far - near );
  4179  
  4180  			te[ 0 ] = x;	te[ 4 ] = 0;	te[ 8 ] = a;	te[ 12 ] = 0;
  4181  			te[ 1 ] = 0;	te[ 5 ] = y;	te[ 9 ] = b;	te[ 13 ] = 0;
  4182  			te[ 2 ] = 0;	te[ 6 ] = 0;	te[ 10 ] = c;	te[ 14 ] = d;
  4183  			te[ 3 ] = 0;	te[ 7 ] = 0;	te[ 11 ] = - 1;	te[ 15 ] = 0;
  4184  
  4185  			return this;
  4186  
  4187  		},
  4188  
  4189  		makeOrthographic: function ( left, right, top, bottom, near, far ) {
  4190  
  4191  			var te = this.elements;
  4192  			var w = 1.0 / ( right - left );
  4193  			var h = 1.0 / ( top - bottom );
  4194  			var p = 1.0 / ( far - near );
  4195  
  4196  			var x = ( right + left ) * w;
  4197  			var y = ( top + bottom ) * h;
  4198  			var z = ( far + near ) * p;
  4199  
  4200  			te[ 0 ] = 2 * w;	te[ 4 ] = 0;	te[ 8 ] = 0;	te[ 12 ] = - x;
  4201  			te[ 1 ] = 0;	te[ 5 ] = 2 * h;	te[ 9 ] = 0;	te[ 13 ] = - y;
  4202  			te[ 2 ] = 0;	te[ 6 ] = 0;	te[ 10 ] = - 2 * p;	te[ 14 ] = - z;
  4203  			te[ 3 ] = 0;	te[ 7 ] = 0;	te[ 11 ] = 0;	te[ 15 ] = 1;
  4204  
  4205  			return this;
  4206  
  4207  		},
  4208  
  4209  		equals: function ( matrix ) {
  4210  
  4211  			var te = this.elements;
  4212  			var me = matrix.elements;
  4213  
  4214  			for ( var i = 0; i < 16; i ++ ) {
  4215  
  4216  				if ( te[ i ] !== me[ i ] ) return false;
  4217  
  4218  			}
  4219  
  4220  			return true;
  4221  
  4222  		},
  4223  
  4224  		fromArray: function ( array, offset ) {
  4225  
  4226  			if ( offset === undefined ) offset = 0;
  4227  
  4228  			for( var i = 0; i < 16; i ++ ) {
  4229  
  4230  				this.elements[ i ] = array[ i + offset ];
  4231  
  4232  			}
  4233  
  4234  			return this;
  4235  
  4236  		},
  4237  
  4238  		toArray: function ( array, offset ) {
  4239  
  4240  			if ( array === undefined ) array = [];
  4241  			if ( offset === undefined ) offset = 0;
  4242  
  4243  			var te = this.elements;
  4244  
  4245  			array[ offset ] = te[ 0 ];
  4246  			array[ offset + 1 ] = te[ 1 ];
  4247  			array[ offset + 2 ] = te[ 2 ];
  4248  			array[ offset + 3 ] = te[ 3 ];
  4249  
  4250  			array[ offset + 4 ] = te[ 4 ];
  4251  			array[ offset + 5 ] = te[ 5 ];
  4252  			array[ offset + 6 ] = te[ 6 ];
  4253  			array[ offset + 7 ] = te[ 7 ];
  4254  
  4255  			array[ offset + 8 ]  = te[ 8 ];
  4256  			array[ offset + 9 ]  = te[ 9 ];
  4257  			array[ offset + 10 ] = te[ 10 ];
  4258  			array[ offset + 11 ] = te[ 11 ];
  4259  
  4260  			array[ offset + 12 ] = te[ 12 ];
  4261  			array[ offset + 13 ] = te[ 13 ];
  4262  			array[ offset + 14 ] = te[ 14 ];
  4263  			array[ offset + 15 ] = te[ 15 ];
  4264  
  4265  			return array;
  4266  
  4267  		}
  4268  
  4269  	};
  4270  
  4271  	/**
  4272  	 * @author mrdoob / http://mrdoob.com/
  4273  	 */
  4274  
  4275  	function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
  4276  
  4277  		images = images !== undefined ? images : [];
  4278  		mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
  4279  
  4280  		Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
  4281  
  4282  		this.flipY = false;
  4283  
  4284  	}
  4285  
  4286  	CubeTexture.prototype = Object.create( Texture.prototype );
  4287  	CubeTexture.prototype.constructor = CubeTexture;
  4288  
  4289  	CubeTexture.prototype.isCubeTexture = true;
  4290  
  4291  	Object.defineProperty( CubeTexture.prototype, 'images', {
  4292  
  4293  		get: function () {
  4294  
  4295  			return this.image;
  4296  
  4297  		},
  4298  
  4299  		set: function ( value ) {
  4300  
  4301  			this.image = value;
  4302  
  4303  		}
  4304  
  4305  	} );
  4306  
  4307  	/**
  4308  	 * @author tschw
  4309  	 *
  4310  	 * Uniforms of a program.
  4311  	 * Those form a tree structure with a special top-level container for the root,
  4312  	 * which you get by calling 'new WebGLUniforms( gl, program, renderer )'.
  4313  	 *
  4314  	 *
  4315  	 * Properties of inner nodes including the top-level container:
  4316  	 *
  4317  	 * .seq - array of nested uniforms
  4318  	 * .map - nested uniforms by name
  4319  	 *
  4320  	 *
  4321  	 * Methods of all nodes except the top-level container:
  4322  	 *
  4323  	 * .setValue( gl, value, [renderer] )
  4324  	 *
  4325  	 * 		uploads a uniform value(s)
  4326  	 *  	the 'renderer' parameter is needed for sampler uniforms
  4327  	 *
  4328  	 *
  4329  	 * Static methods of the top-level container (renderer factorizations):
  4330  	 *
  4331  	 * .upload( gl, seq, values, renderer )
  4332  	 *
  4333  	 * 		sets uniforms in 'seq' to 'values[id].value'
  4334  	 *
  4335  	 * .seqWithValue( seq, values ) : filteredSeq
  4336  	 *
  4337  	 * 		filters 'seq' entries with corresponding entry in values
  4338  	 *
  4339  	 *
  4340  	 * Methods of the top-level container (renderer factorizations):
  4341  	 *
  4342  	 * .setValue( gl, name, value )
  4343  	 *
  4344  	 * 		sets uniform with  name 'name' to 'value'
  4345  	 *
  4346  	 * .set( gl, obj, prop )
  4347  	 *
  4348  	 * 		sets uniform from object and property with same name than uniform
  4349  	 *
  4350  	 * .setOptional( gl, obj, prop )
  4351  	 *
  4352  	 * 		like .set for an optional property of the object
  4353  	 *
  4354  	 */
  4355  
  4356  	var emptyTexture = new Texture();
  4357  	var emptyCubeTexture = new CubeTexture();
  4358  
  4359  	// --- Base for inner nodes (including the root) ---
  4360  
  4361  	function UniformContainer() {
  4362  
  4363  		this.seq = [];
  4364  		this.map = {};
  4365  
  4366  	}
  4367  
  4368  	// --- Utilities ---
  4369  
  4370  	// Array Caches (provide typed arrays for temporary by size)
  4371  
  4372  	var arrayCacheF32 = [];
  4373  	var arrayCacheI32 = [];
  4374  
  4375  	// Flattening for arrays of vectors and matrices
  4376  
  4377  	function flatten( array, nBlocks, blockSize ) {
  4378  
  4379  		var firstElem = array[ 0 ];
  4380  
  4381  		if ( firstElem <= 0 || firstElem > 0 ) return array;
  4382  		// unoptimized: ! isNaN( firstElem )
  4383  		// see http://jacksondunstan.com/articles/983
  4384  
  4385  		var n = nBlocks * blockSize,
  4386  			r = arrayCacheF32[ n ];
  4387  
  4388  		if ( r === undefined ) {
  4389  
  4390  			r = new Float32Array( n );
  4391  			arrayCacheF32[ n ] = r;
  4392  
  4393  		}
  4394  
  4395  		if ( nBlocks !== 0 ) {
  4396  
  4397  			firstElem.toArray( r, 0 );
  4398  
  4399  			for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) {
  4400  
  4401  				offset += blockSize;
  4402  				array[ i ].toArray( r, offset );
  4403  
  4404  			}
  4405  
  4406  		}
  4407  
  4408  		return r;
  4409  
  4410  	}
  4411  
  4412  	// Texture unit allocation
  4413  
  4414  	function allocTexUnits( renderer, n ) {
  4415  
  4416  		var r = arrayCacheI32[ n ];
  4417  
  4418  		if ( r === undefined ) {
  4419  
  4420  			r = new Int32Array( n );
  4421  			arrayCacheI32[ n ] = r;
  4422  
  4423  		}
  4424  
  4425  		for ( var i = 0; i !== n; ++ i )
  4426  			r[ i ] = renderer.allocTextureUnit();
  4427  
  4428  		return r;
  4429  
  4430  	}
  4431  
  4432  	// --- Setters ---
  4433  
  4434  	// Note: Defining these methods externally, because they come in a bunch
  4435  	// and this way their names minify.
  4436  
  4437  	// Single scalar
  4438  
  4439  	function setValue1f( gl, v ) { gl.uniform1f( this.addr, v ); }
  4440  	function setValue1i( gl, v ) { gl.uniform1i( this.addr, v ); }
  4441  
  4442  	// Single float vector (from flat array or THREE.VectorN)
  4443  
  4444  	function setValue2fv( gl, v ) {
  4445  
  4446  		if ( v.x === undefined ) gl.uniform2fv( this.addr, v );
  4447  		else gl.uniform2f( this.addr, v.x, v.y );
  4448  
  4449  	}
  4450  
  4451  	function setValue3fv( gl, v ) {
  4452  
  4453  		if ( v.x !== undefined )
  4454  			gl.uniform3f( this.addr, v.x, v.y, v.z );
  4455  		else if ( v.r !== undefined )
  4456  			gl.uniform3f( this.addr, v.r, v.g, v.b );
  4457  		else
  4458  			gl.uniform3fv( this.addr, v );
  4459  
  4460  	}
  4461  
  4462  	function setValue4fv( gl, v ) {
  4463  
  4464  		if ( v.x === undefined ) gl.uniform4fv( this.addr, v );
  4465  		else gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
  4466  
  4467  	}
  4468  
  4469  	// Single matrix (from flat array or MatrixN)
  4470  
  4471  	function setValue2fm( gl, v ) {
  4472  
  4473  		gl.uniformMatrix2fv( this.addr, false, v.elements || v );
  4474  
  4475  	}
  4476  
  4477  	function setValue3fm( gl, v ) {
  4478  
  4479  		gl.uniformMatrix3fv( this.addr, false, v.elements || v );
  4480  
  4481  	}
  4482  
  4483  	function setValue4fm( gl, v ) {
  4484  
  4485  		gl.uniformMatrix4fv( this.addr, false, v.elements || v );
  4486  
  4487  	}
  4488  
  4489  	// Single texture (2D / Cube)
  4490  
  4491  	function setValueT1( gl, v, renderer ) {
  4492  
  4493  		var unit = renderer.allocTextureUnit();
  4494  		gl.uniform1i( this.addr, unit );
  4495  		renderer.setTexture2D( v || emptyTexture, unit );
  4496  
  4497  	}
  4498  
  4499  	function setValueT6( gl, v, renderer ) {
  4500  
  4501  		var unit = renderer.allocTextureUnit();
  4502  		gl.uniform1i( this.addr, unit );
  4503  		renderer.setTextureCube( v || emptyCubeTexture, unit );
  4504  
  4505  	}
  4506  
  4507  	// Integer / Boolean vectors or arrays thereof (always flat arrays)
  4508  
  4509  	function setValue2iv( gl, v ) { gl.uniform2iv( this.addr, v ); }
  4510  	function setValue3iv( gl, v ) { gl.uniform3iv( this.addr, v ); }
  4511  	function setValue4iv( gl, v ) { gl.uniform4iv( this.addr, v ); }
  4512  
  4513  	// Helper to pick the right setter for the singular case
  4514  
  4515  	function getSingularSetter( type ) {
  4516  
  4517  		switch ( type ) {
  4518  
  4519  			case 0x1406: return setValue1f; // FLOAT
  4520  			case 0x8b50: return setValue2fv; // _VEC2
  4521  			case 0x8b51: return setValue3fv; // _VEC3
  4522  			case 0x8b52: return setValue4fv; // _VEC4
  4523  
  4524  			case 0x8b5a: return setValue2fm; // _MAT2
  4525  			case 0x8b5b: return setValue3fm; // _MAT3
  4526  			case 0x8b5c: return setValue4fm; // _MAT4
  4527  
  4528  			case 0x8b5e: return setValueT1; // SAMPLER_2D
  4529  			case 0x8b60: return setValueT6; // SAMPLER_CUBE
  4530  
  4531  			case 0x1404: case 0x8b56: return setValue1i; // INT, BOOL
  4532  			case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
  4533  			case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
  4534  			case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
  4535  
  4536  		}
  4537  
  4538  	}
  4539  
  4540  	// Array of scalars
  4541  
  4542  	function setValue1fv( gl, v ) { gl.uniform1fv( this.addr, v ); }
  4543  	function setValue1iv( gl, v ) { gl.uniform1iv( this.addr, v ); }
  4544  
  4545  	// Array of vectors (flat or from THREE classes)
  4546  
  4547  	function setValueV2a( gl, v ) {
  4548  
  4549  		gl.uniform2fv( this.addr, flatten( v, this.size, 2 ) );
  4550  
  4551  	}
  4552  
  4553  	function setValueV3a( gl, v ) {
  4554  
  4555  		gl.uniform3fv( this.addr, flatten( v, this.size, 3 ) );
  4556  
  4557  	}
  4558  
  4559  	function setValueV4a( gl, v ) {
  4560  
  4561  		gl.uniform4fv( this.addr, flatten( v, this.size, 4 ) );
  4562  
  4563  	}
  4564  
  4565  	// Array of matrices (flat or from THREE clases)
  4566  
  4567  	function setValueM2a( gl, v ) {
  4568  
  4569  		gl.uniformMatrix2fv( this.addr, false, flatten( v, this.size, 4 ) );
  4570  
  4571  	}
  4572  
  4573  	function setValueM3a( gl, v ) {
  4574  
  4575  		gl.uniformMatrix3fv( this.addr, false, flatten( v, this.size, 9 ) );
  4576  
  4577  	}
  4578  
  4579  	function setValueM4a( gl, v ) {
  4580  
  4581  		gl.uniformMatrix4fv( this.addr, false, flatten( v, this.size, 16 ) );
  4582  
  4583  	}
  4584  
  4585  	// Array of textures (2D / Cube)
  4586  
  4587  	function setValueT1a( gl, v, renderer ) {
  4588  
  4589  		var n = v.length,
  4590  			units = allocTexUnits( renderer, n );
  4591  
  4592  		gl.uniform1iv( this.addr, units );
  4593  
  4594  		for ( var i = 0; i !== n; ++ i ) {
  4595  
  4596  			renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] );
  4597  
  4598  		}
  4599  
  4600  	}
  4601  
  4602  	function setValueT6a( gl, v, renderer ) {
  4603  
  4604  		var n = v.length,
  4605  			units = allocTexUnits( renderer, n );
  4606  
  4607  		gl.uniform1iv( this.addr, units );
  4608  
  4609  		for ( var i = 0; i !== n; ++ i ) {
  4610  
  4611  			renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
  4612  
  4613  		}
  4614  
  4615  	}
  4616  
  4617  	// Helper to pick the right setter for a pure (bottom-level) array
  4618  
  4619  	function getPureArraySetter( type ) {
  4620  
  4621  		switch ( type ) {
  4622  
  4623  			case 0x1406: return setValue1fv; // FLOAT
  4624  			case 0x8b50: return setValueV2a; // _VEC2
  4625  			case 0x8b51: return setValueV3a; // _VEC3
  4626  			case 0x8b52: return setValueV4a; // _VEC4
  4627  
  4628  			case 0x8b5a: return setValueM2a; // _MAT2
  4629  			case 0x8b5b: return setValueM3a; // _MAT3
  4630  			case 0x8b5c: return setValueM4a; // _MAT4
  4631  
  4632  			case 0x8b5e: return setValueT1a; // SAMPLER_2D
  4633  			case 0x8b60: return setValueT6a; // SAMPLER_CUBE
  4634  
  4635  			case 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL
  4636  			case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
  4637  			case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
  4638  			case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
  4639  
  4640  		}
  4641  
  4642  	}
  4643  
  4644  	// --- Uniform Classes ---
  4645  
  4646  	function SingleUniform( id, activeInfo, addr ) {
  4647  
  4648  		this.id = id;
  4649  		this.addr = addr;
  4650  		this.setValue = getSingularSetter( activeInfo.type );
  4651  
  4652  		// this.path = activeInfo.name; // DEBUG
  4653  
  4654  	}
  4655  
  4656  	function PureArrayUniform( id, activeInfo, addr ) {
  4657  
  4658  		this.id = id;
  4659  		this.addr = addr;
  4660  		this.size = activeInfo.size;
  4661  		this.setValue = getPureArraySetter( activeInfo.type );
  4662  
  4663  		// this.path = activeInfo.name; // DEBUG
  4664  
  4665  	}
  4666  
  4667  	function StructuredUniform( id ) {
  4668  
  4669  		this.id = id;
  4670  
  4671  		UniformContainer.call( this ); // mix-in
  4672  
  4673  	}
  4674  
  4675  	StructuredUniform.prototype.setValue = function( gl, value ) {
  4676  
  4677  		// Note: Don't need an extra 'renderer' parameter, since samplers
  4678  		// are not allowed in structured uniforms.
  4679  
  4680  		var seq = this.seq;
  4681  
  4682  		for ( var i = 0, n = seq.length; i !== n; ++ i ) {
  4683  
  4684  			var u = seq[ i ];
  4685  			u.setValue( gl, value[ u.id ] );
  4686  
  4687  		}
  4688  
  4689  	};
  4690  
  4691  	// --- Top-level ---
  4692  
  4693  	// Parser - builds up the property tree from the path strings
  4694  
  4695  	var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g;
  4696  
  4697  	// extracts
  4698  	// 	- the identifier (member name or array index)
  4699  	//  - followed by an optional right bracket (found when array index)
  4700  	//  - followed by an optional left bracket or dot (type of subscript)
  4701  	//
  4702  	// Note: These portions can be read in a non-overlapping fashion and
  4703  	// allow straightforward parsing of the hierarchy that WebGL encodes
  4704  	// in the uniform names.
  4705  
  4706  	function addUniform( container, uniformObject ) {
  4707  
  4708  		container.seq.push( uniformObject );
  4709  		container.map[ uniformObject.id ] = uniformObject;
  4710  
  4711  	}
  4712  
  4713  	function parseUniform( activeInfo, addr, container ) {
  4714  
  4715  		var path = activeInfo.name,
  4716  			pathLength = path.length;
  4717  
  4718  		// reset RegExp object, because of the early exit of a previous run
  4719  		RePathPart.lastIndex = 0;
  4720  
  4721  		for (; ;) {
  4722  
  4723  			var match = RePathPart.exec( path ),
  4724  				matchEnd = RePathPart.lastIndex,
  4725  
  4726  				id = match[ 1 ],
  4727  				idIsIndex = match[ 2 ] === ']',
  4728  				subscript = match[ 3 ];
  4729  
  4730  			if ( idIsIndex ) id = id | 0; // convert to integer
  4731  
  4732  			if ( subscript === undefined ||
  4733  					subscript === '[' && matchEnd + 2 === pathLength ) {
  4734  				// bare name or "pure" bottom-level array "[0]" suffix
  4735  
  4736  				addUniform( container, subscript === undefined ?
  4737  						new SingleUniform( id, activeInfo, addr ) :
  4738  						new PureArrayUniform( id, activeInfo, addr ) );
  4739  
  4740  				break;
  4741  
  4742  			} else {
  4743  				// step into inner node / create it in case it doesn't exist
  4744  
  4745  				var map = container.map,
  4746  					next = map[ id ];
  4747  
  4748  				if ( next === undefined ) {
  4749  
  4750  					next = new StructuredUniform( id );
  4751  					addUniform( container, next );
  4752  
  4753  				}
  4754  
  4755  				container = next;
  4756  
  4757  			}
  4758  
  4759  		}
  4760  
  4761  	}
  4762  
  4763  	// Root Container
  4764  
  4765  	function WebGLUniforms( gl, program, renderer ) {
  4766  
  4767  		UniformContainer.call( this );
  4768  
  4769  		this.renderer = renderer;
  4770  
  4771  		var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
  4772  
  4773  		for ( var i = 0; i < n; ++ i ) {
  4774  
  4775  			var info = gl.getActiveUniform( program, i ),
  4776  				path = info.name,
  4777  				addr = gl.getUniformLocation( program, path );
  4778  
  4779  			parseUniform( info, addr, this );
  4780  
  4781  		}
  4782  
  4783  	}
  4784  
  4785  	WebGLUniforms.prototype.setValue = function( gl, name, value ) {
  4786  
  4787  		var u = this.map[ name ];
  4788  
  4789  		if ( u !== undefined ) u.setValue( gl, value, this.renderer );
  4790  
  4791  	};
  4792  
  4793  	WebGLUniforms.prototype.set = function( gl, object, name ) {
  4794  
  4795  		var u = this.map[ name ];
  4796  
  4797  		if ( u !== undefined ) u.setValue( gl, object[ name ], this.renderer );
  4798  
  4799  	};
  4800  
  4801  	WebGLUniforms.prototype.setOptional = function( gl, object, name ) {
  4802  
  4803  		var v = object[ name ];
  4804  
  4805  		if ( v !== undefined ) this.setValue( gl, name, v );
  4806  
  4807  	};
  4808  
  4809  
  4810  	// Static interface
  4811  
  4812  	WebGLUniforms.upload = function( gl, seq, values, renderer ) {
  4813  
  4814  		for ( var i = 0, n = seq.length; i !== n; ++ i ) {
  4815  
  4816  			var u = seq[ i ],
  4817  				v = values[ u.id ];
  4818  
  4819  			if ( v.needsUpdate !== false ) {
  4820  				// note: always updating when .needsUpdate is undefined
  4821  
  4822  				u.setValue( gl, v.value, renderer );
  4823  
  4824  			}
  4825  
  4826  		}
  4827  
  4828  	};
  4829  
  4830  	WebGLUniforms.seqWithValue = function( seq, values ) {
  4831  
  4832  		var r = [];
  4833  
  4834  		for ( var i = 0, n = seq.length; i !== n; ++ i ) {
  4835  
  4836  			var u = seq[ i ];
  4837  			if ( u.id in values ) r.push( u );
  4838  
  4839  		}
  4840  
  4841  		return r;
  4842  
  4843  	};
  4844  
  4845  	/**
  4846  	 * Uniform Utilities
  4847  	 */
  4848  
  4849  	var UniformsUtils = {
  4850  
  4851  		merge: function ( uniforms ) {
  4852  
  4853  			var merged = {};
  4854  
  4855  			for ( var u = 0; u < uniforms.length; u ++ ) {
  4856  
  4857  				var tmp = this.clone( uniforms[ u ] );
  4858  
  4859  				for ( var p in tmp ) {
  4860  
  4861  					merged[ p ] = tmp[ p ];
  4862  
  4863  				}
  4864  
  4865  			}
  4866  
  4867  			return merged;
  4868  
  4869  		},
  4870  
  4871  		clone: function ( uniforms_src ) {
  4872  
  4873  			var uniforms_dst = {};
  4874  
  4875  			for ( var u in uniforms_src ) {
  4876  
  4877  				uniforms_dst[ u ] = {};
  4878  
  4879  				for ( var p in uniforms_src[ u ] ) {
  4880  
  4881  					var parameter_src = uniforms_src[ u ][ p ];
  4882  
  4883  					if ( parameter_src && ( parameter_src.isColor ||
  4884  						parameter_src.isMatrix3 || parameter_src.isMatrix4 ||
  4885  						parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 ||
  4886  						parameter_src.isTexture ) ) {
  4887  
  4888  						uniforms_dst[ u ][ p ] = parameter_src.clone();
  4889  
  4890  					} else if ( Array.isArray( parameter_src ) ) {
  4891  
  4892  						uniforms_dst[ u ][ p ] = parameter_src.slice();
  4893  
  4894  					} else {
  4895  
  4896  						uniforms_dst[ u ][ p ] = parameter_src;
  4897  
  4898  					}
  4899  
  4900  				}
  4901  
  4902  			}
  4903  
  4904  			return uniforms_dst;
  4905  
  4906  		}
  4907  
  4908  	};
  4909  
  4910  	var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n";
  4911  
  4912  	var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n";
  4913  
  4914  	var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n";
  4915  
  4916  	var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif\n";
  4917  
  4918  	var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
  4919  
  4920  	var begin_vertex = "\nvec3 transformed = vec3( position );\n";
  4921  
  4922  	var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n";
  4923  
  4924  	var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t\tif( decayExponent > 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t\t}\n\t\treturn 1.0;\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 ltcTextureCoords( const in GeometricContext geometry, const in float roughness ) {\n\tconst float LUT_SIZE  = 64.0;\n\tconst float LUT_SCALE = (LUT_SIZE - 1.0)/LUT_SIZE;\n\tconst float LUT_BIAS  = 0.5/LUT_SIZE;\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 P = geometry.position;\n\tfloat theta = acos( dot( N, V ) );\n\tvec2 uv = vec2(\n\t\tsqrt( saturate( roughness ) ),\n\t\tsaturate( theta / ( 0.5 * PI ) ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nvoid clipQuadToHorizon( inout vec3 L[5], out int n ) {\n\tint config = 0;\n\tif ( L[0].z > 0.0 ) config += 1;\n\tif ( L[1].z > 0.0 ) config += 2;\n\tif ( L[2].z > 0.0 ) config += 4;\n\tif ( L[3].z > 0.0 ) config += 8;\n\tn = 0;\n\tif ( config == 0 ) {\n\t} else if ( config == 1 ) {\n\t\tn = 3;\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t\tL[2] = -L[3].z * L[0] + L[0].z * L[3];\n\t} else if ( config == 2 ) {\n\t\tn = 3;\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t} else if ( config == 3 ) {\n\t\tn = 4;\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t\tL[3] = -L[3].z * L[0] + L[0].z * L[3];\n\t} else if ( config == 4 ) {\n\t\tn = 3;\n\t\tL[0] = -L[3].z * L[2] + L[2].z * L[3];\n\t\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\n\t} else if ( config == 5 ) {\n\t\tn = 0;\n\t} else if ( config == 6 ) {\n\t\tn = 4;\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\n\t} else if ( config == 7 ) {\n\t\tn = 5;\n\t\tL[4] = -L[3].z * L[0] + L[0].z * L[3];\n\t\tL[3] = -L[3].z * L[2] + L[2].z * L[3];\n\t} else if ( config == 8 ) {\n\t\tn = 3;\n\t\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\n\t\tL[1] = -L[2].z * L[3] + L[3].z * L[2];\n\t\tL[2] =  L[3];\n\t} else if ( config == 9 ) {\n\t\tn = 4;\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t\tL[2] = -L[2].z * L[3] + L[3].z * L[2];\n\t} else if ( config == 10 ) {\n\t\tn = 0;\n\t} else if ( config == 11 ) {\n\t\tn = 5;\n\t\tL[4] = L[3];\n\t\tL[3] = -L[2].z * L[3] + L[3].z * L[2];\n\t\tL[2] = -L[2].z * L[1] + L[1].z * L[2];\n\t} else if ( config == 12 ) {\n\t\tn = 4;\n\t\tL[1] = -L[1].z * L[2] + L[2].z * L[1];\n\t\tL[0] = -L[0].z * L[3] + L[3].z * L[0];\n\t} else if ( config == 13 ) {\n\t\tn = 5;\n\t\tL[4] = L[3];\n\t\tL[3] = L[2];\n\t\tL[2] = -L[1].z * L[2] + L[2].z * L[1];\n\t\tL[1] = -L[1].z * L[0] + L[0].z * L[1];\n\t} else if ( config == 14 ) {\n\t\tn = 5;\n\t\tL[4] = -L[0].z * L[3] + L[3].z * L[0];\n\t\tL[0] = -L[0].z * L[1] + L[1].z * L[0];\n\t} else if ( config == 15 ) {\n\t\tn = 4;\n\t}\n\tif ( n == 3 )\n\t\tL[3] = L[0];\n\tif ( n == 4 )\n\t\tL[4] = L[0];\n}\nfloat integrateLtcBrdfOverRectEdge( vec3 v1, vec3 v2 ) {\n\tfloat cosTheta = dot( v1, v2 );\n\tfloat theta = acos( cosTheta );\n\tfloat res = cross( v1, v2 ).z * ( ( theta > 0.001 ) ? theta / sin( theta ) : 1.0 );\n\treturn res;\n}\nvoid initRectPoints( const in vec3 pos, const in vec3 halfWidth, const in vec3 halfHeight, out vec3 rectPoints[4] ) {\n\trectPoints[0] = pos - halfWidth - halfHeight;\n\trectPoints[1] = pos + halfWidth - halfHeight;\n\trectPoints[2] = pos + halfWidth + halfHeight;\n\trectPoints[3] = pos - halfWidth + halfHeight;\n}\nvec3 integrateLtcBrdfOverRect( const in GeometricContext geometry, const in mat3 brdfMat, const in vec3 rectPoints[4] ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 P = geometry.position;\n\tvec3 T1, T2;\n\tT1 = normalize(V - N * dot( V, N ));\n\tT2 = - cross( N, T1 );\n\tmat3 brdfWrtSurface = brdfMat * transpose( mat3( T1, T2, N ) );\n\tvec3 clippedRect[5];\n\tclippedRect[0] = brdfWrtSurface * ( rectPoints[0] - P );\n\tclippedRect[1] = brdfWrtSurface * ( rectPoints[1] - P );\n\tclippedRect[2] = brdfWrtSurface * ( rectPoints[2] - P );\n\tclippedRect[3] = brdfWrtSurface * ( rectPoints[3] - P );\n\tint n;\n\tclipQuadToHorizon(clippedRect, n);\n\tif ( n == 0 )\n\t\treturn vec3( 0, 0, 0 );\n\tclippedRect[0] = normalize( clippedRect[0] );\n\tclippedRect[1] = normalize( clippedRect[1] );\n\tclippedRect[2] = normalize( clippedRect[2] );\n\tclippedRect[3] = normalize( clippedRect[3] );\n\tclippedRect[4] = normalize( clippedRect[4] );\n\tfloat sum = 0.0;\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[0], clippedRect[1] );\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[1], clippedRect[2] );\n\tsum += integrateLtcBrdfOverRectEdge( clippedRect[2], clippedRect[3] );\n\tif (n >= 4)\n\t\tsum += integrateLtcBrdfOverRectEdge( clippedRect[3], clippedRect[4] );\n\tif (n == 5)\n\t\tsum += integrateLtcBrdfOverRectEdge( clippedRect[4], clippedRect[0] );\n\tsum = max( 0.0, sum );\n\tvec3 Lo_i = vec3( sum, sum, sum );\n\treturn Lo_i;\n}\nvec3 Rect_Area_Light_Specular_Reflectance(\n\t\tconst in GeometricContext geometry,\n\t\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight,\n\t\tconst in float roughness,\n\t\tconst in sampler2D ltcMat, const in sampler2D ltcMag ) {\n\tvec3 rectPoints[4];\n\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\n\tvec2 uv = ltcTextureCoords( geometry, roughness );\n\tvec4 brdfLtcApproxParams, t;\n\tbrdfLtcApproxParams = texture2D( ltcMat, uv );\n\tt = texture2D( ltcMat, uv );\n\tfloat brdfLtcScalar = texture2D( ltcMag, uv ).a;\n\tmat3 brdfLtcApproxMat = mat3(\n\t\tvec3(   1,   0, t.y ),\n\t\tvec3(   0, t.z,   0 ),\n\t\tvec3( t.w,   0, t.x )\n\t);\n\tvec3 specularReflectance = integrateLtcBrdfOverRect( geometry, brdfLtcApproxMat, rectPoints );\n\tspecularReflectance *= brdfLtcScalar;\n\treturn specularReflectance;\n}\nvec3 Rect_Area_Light_Diffuse_Reflectance(\n\t\tconst in GeometricContext geometry,\n\t\tconst in vec3 lightPos, const in vec3 lightHalfWidth, const in vec3 lightHalfHeight ) {\n\tvec3 rectPoints[4];\n\tinitRectPoints( lightPos, lightHalfWidth, lightHalfHeight, rectPoints );\n\tmat3 diffuseBrdfMat = mat3(1);\n\tvec3 diffuseReflectance = integrateLtcBrdfOverRect( geometry, diffuseBrdfMat, rectPoints );\n\treturn diffuseReflectance;\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n";
  4925  
  4926  	var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = dFdx( surf_pos );\n\t\tvec3 vSigmaY = dFdy( surf_pos );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n";
  4927  
  4928  	var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\n\t\tvec4 plane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t\t\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\n\t\t\tvec4 plane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t\n\t#endif\n#endif\n";
  4929  
  4930  	var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n";
  4931  
  4932  	var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n";
  4933  
  4934  	var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n";
  4935  
  4936  	var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif";
  4937  
  4938  	var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n";
  4939  
  4940  	var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif";
  4941  
  4942  	var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif";
  4943  
  4944  	var common = "#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transpose( const in mat3 v ) {\n\tmat3 tmp;\n\ttmp[0] = vec3(v[0].x, v[1].x, v[2].x);\n\ttmp[1] = vec3(v[0].y, v[1].y, v[2].y);\n\ttmp[2] = vec3(v[0].z, v[1].z, v[2].z);\n\treturn tmp;\n}\n";
  4945  
  4946  	var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1  (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale =  bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif\n";
  4947  
  4948  	var defaultnormal_vertex = "#ifdef FLIP_SIDED\n\tobjectNormal = -objectNormal;\n#endif\nvec3 transformedNormal = normalMatrix * objectNormal;\n";
  4949  
  4950  	var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n";
  4951  
  4952  	var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normal * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n";
  4953  
  4954  	var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n";
  4955  
  4956  	var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n";
  4957  
  4958  	var encodings_fragment = "  gl_FragColor = linearToOutputTexel( gl_FragColor );\n";
  4959  
  4960  	var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.xyz * value.w * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat M      = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM            = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat D      = max( maxRange / maxRGB, 1.0 );\n\tD            = min( floor( D ) / 255.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value )  {\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\n\tXp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract(Le);\n\tvResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n\treturn vec4( max(vRGB, 0.0), 1.0 );\n}\n";
  4961  
  4962  	var envmap_fragment = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\tsampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\tvec3 reflectView = flipNormal * normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif\n";
  4963  
  4964  	var envmap_pars_fragment = "#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n";
  4965  
  4966  	var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif\n";
  4967  
  4968  	var envmap_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif\n";
  4969  
  4970  	var fog_vertex = "\n#ifdef USE_FOG\nfogDepth = -mvPosition.z;\n#endif";
  4971  
  4972  	var fog_pars_vertex = "#ifdef USE_FOG\n  varying float fogDepth;\n#endif\n";
  4973  
  4974  	var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif\n";
  4975  
  4976  	var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif\n";
  4977  
  4978  	var gradientmap_pars_fragment = "#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif\n";
  4979  
  4980  	var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n";
  4981  
  4982  	var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
  4983  
  4984  	var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif\n";
  4985  
  4986  	var lights_pars = "uniform vec3 ambientLightColor;\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight  ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltcMat;\tuniform sampler2D ltcMag;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = saturate( reflectVec.y * 0.5 + 0.5 );\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif\n";
  4987  
  4988  	var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n";
  4989  
  4990  	var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_BlinnPhong( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 matDiffColor = material.diffuseColor;\n\t\tvec3 matSpecColor = material.specularColor;\n\t\tvec3 lightColor   = rectAreaLight.color;\n\t\tfloat roughness = BlinnExponentToGGXRoughness( material.specularShininess );\n\t\tvec3 spec = Rect_Area_Light_Specular_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\n\t\t\t\troughness,\n\t\t\t\tltcMat, ltcMag );\n\t\tvec3 diff = Rect_Area_Light_Diffuse_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\n\t\treflectedLight.directSpecular += lightColor * matSpecColor * spec / PI2;\n\t\treflectedLight.directDiffuse  += lightColor * matDiffColor * diff / PI2;\n\t}\n#endif\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n";
  4991  
  4992  	var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif\n";
  4993  
  4994  	var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 matDiffColor = material.diffuseColor;\n\t\tvec3 matSpecColor = material.specularColor;\n\t\tvec3 lightColor   = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 spec = Rect_Area_Light_Specular_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight,\n\t\t\t\troughness,\n\t\t\t\tltcMat, ltcMag );\n\t\tvec3 diff = Rect_Area_Light_Diffuse_Reflectance(\n\t\t\t\tgeometry,\n\t\t\t\trectAreaLight.position, rectAreaLight.halfWidth, rectAreaLight.halfHeight );\n\t\treflectedLight.directSpecular += lightColor * matSpecColor * spec;\n\t\treflectedLight.directDiffuse  += lightColor * matDiffColor * diff;\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\n#define Material_BlinnShininessExponent( material )   GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material )   GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}\n";
  4995  
  4996  	var lights_template = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\n\t#endif\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\n\t#ifndef STANDARD\n\t\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\n\t#else\n\t\tvec3 clearCoatRadiance = vec3( 0.0 );\n\t#endif\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n";
  4997  
  4998  	var logdepthbuf_fragment = "#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n#endif";
  4999  
  5000  	var logdepthbuf_pars_fragment = "#ifdef USE_LOGDEPTHBUF\n\tuniform float logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n#endif\n";
  5001  
  5002  	var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n\tuniform float logDepthBufFC;\n#endif";
  5003  
  5004  	var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\t#endif\n#endif\n";
  5005  
  5006  	var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n";
  5007  
  5008  	var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n";
  5009  
  5010  	var map_particle_fragment = "#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n";
  5011  
  5012  	var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n#endif\n";
  5013  
  5014  	var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.r;\n#endif\n";
  5015  
  5016  	var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
  5017  
  5018  	var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif\n";
  5019  
  5020  	var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif";
  5021  
  5022  	var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif\n";
  5023  
  5024  	var normal_flip = "#ifdef DOUBLE_SIDED\n\tfloat flipNormal = ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n#else\n\tfloat flipNormal = 1.0;\n#endif\n";
  5025  
  5026  	var normal_fragment = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal ) * flipNormal;\n#endif\n#ifdef USE_NORMALMAP\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n";
  5027  
  5028  	var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif\n";
  5029  
  5030  	var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 1.0 - 2.0 * rgb.xyz;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256.,  256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}\n";
  5031  
  5032  	var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n";
  5033  
  5034  	var project_vertex = "#ifdef USE_SKINNING\n\tvec4 mvPosition = modelViewMatrix * skinned;\n#else\n\tvec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\n#endif\ngl_Position = projectionMatrix * mvPosition;\n";
  5035  
  5036  	var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.r;\n#endif\n";
  5037  
  5038  	var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
  5039  
  5040  	var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\treturn (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn 1.0;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\tfloat dp = ( length( lightToPosition ) - shadowBias ) / 1000.0;\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif\n";
  5041  
  5042  	var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n#endif\n";
  5043  
  5044  	var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif\n";
  5045  
  5046  	var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}\n";
  5047  
  5048  	var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif";
  5049  
  5050  	var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureWidth;\n\t\tuniform int boneTextureHeight;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureWidth ) );\n\t\t\tfloat y = floor( j / float( boneTextureWidth ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureWidth );\n\t\t\tfloat dy = 1.0 / float( boneTextureHeight );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif\n";
  5051  
  5052  	var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\tskinned  = bindMatrixInverse * skinned;\n#endif\n";
  5053  
  5054  	var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix  = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif\n";
  5055  
  5056  	var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif";
  5057  
  5058  	var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
  5059  
  5060  	var tonemapping_fragment = "#if defined( TONE_MAPPING )\n  gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n";
  5061  
  5062  	var tonemapping_pars_fragment = "#define saturate(a) clamp( a, 0.0, 1.0 )\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\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 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n";
  5063  
  5064  	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 )\n\tvarying vec2 vUv;\n#endif";
  5065  
  5066  	var uv_pars_vertex = "#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 )\n\tvarying vec2 vUv;\n\tuniform vec4 offsetRepeat;\n#endif\n";
  5067  
  5068  	var uv_vertex = "#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 )\n\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n#endif";
  5069  
  5070  	var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";
  5071  
  5072  	var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif";
  5073  
  5074  	var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif";
  5075  
  5076  	var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\t#ifdef USE_SKINNING\n\t\tvec4 worldPosition = modelMatrix * skinned;\n\t#else\n\t\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n\t#endif\n#endif\n";
  5077  
  5078  	var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n";
  5079  
  5080  	var cube_vert = "varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}\n";
  5081  
  5082  	var depth_frag = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <logdepthbuf_fragment>\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n";
  5083  
  5084  	var depth_vert = "#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <skinbase_vertex>\n\t#include <begin_vertex>\n\t#include <displacementmap_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n}\n";
  5085  
  5086  	var distanceRGBA_frag = "uniform vec3 lightPos;\nvarying vec4 vWorldPosition;\n#include <common>\n#include <packing>\n#include <clipping_planes_pars_fragment>\nvoid main () {\n\t#include <clipping_planes_fragment>\n\tgl_FragColor = packDepthToRGBA( length( vWorldPosition.xyz - lightPos.xyz ) / 1000.0 );\n}\n";
  5087  
  5088  	var distanceRGBA_vert = "varying vec4 vWorldPosition;\n#include <common>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <skinbase_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\tvWorldPosition = worldPosition;\n}\n";
  5089  
  5090  	var equirect_frag = "uniform sampler2D tEquirect;\nuniform float tFlip;\nvarying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\n\tvec2 sampleUV;\n\tsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n";
  5091  
  5092  	var equirect_vert = "varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}\n";
  5093  
  5094  	var linedashed_frag = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <color_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
  5095  
  5096  	var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}\n";
  5097  
  5098  	var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include <aomap_fragment>\n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include <normal_flip>\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
  5099  
  5100  	var meshbasic_vert = "#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_ENVMAP\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <envmap_vertex>\n\t#include <fog_vertex>\n}\n";
  5101  
  5102  	var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include <common>\n#include <packing>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <bsdfs>\n#include <lights_pars>\n#include <fog_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <emissivemap_fragment>\n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include <lightmap_fragment>\n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <normal_flip>\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
  5103  
  5104  	var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <bsdfs>\n#include <lights_pars>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <lights_lambert_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
  5105  
  5106  	var meshphong_frag = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <gradientmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars>\n#include <lights_phong_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_flip>\n\t#include <normal_fragment>\n\t#include <emissivemap_fragment>\n\t#include <lights_phong_fragment>\n\t#include <lights_template>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
  5107  
  5108  	var meshphong_vert = "#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <displacementmap_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
  5109  
  5110  	var meshphysical_frag = "#define PHYSICAL\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifndef STANDARD\n\tuniform float clearCoat;\n\tuniform float clearCoatRoughness;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <packing>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <cube_uv_reflection_fragment>\n#include <lights_pars>\n#include <lights_physical_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <roughnessmap_pars_fragment>\n#include <metalnessmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <roughnessmap_fragment>\n\t#include <metalnessmap_fragment>\n\t#include <normal_flip>\n\t#include <normal_fragment>\n\t#include <emissivemap_fragment>\n\t#include <lights_physical_fragment>\n\t#include <lights_template>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
  5111  
  5112  	var meshphysical_vert = "#define PHYSICAL\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <displacementmap_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
  5113  
  5114  	var normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <packing>\n#include <uv_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\nvoid main() {\n\t#include <logdepthbuf_fragment>\n\t#include <normal_flip>\n\t#include <normal_fragment>\n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n";
  5115  
  5116  	var normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <displacementmap_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}\n";
  5117  
  5118  	var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <fog_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_particle_fragment>\n\t#include <color_fragment>\n\t#include <alphatest_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
  5119  
  5120  	var points_vert = "uniform float size;\nuniform float scale;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
  5121  
  5122  	var shadow_frag = "uniform float opacity;\n#include <common>\n#include <packing>\n#include <bsdfs>\n#include <lights_pars>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\tgl_FragColor = vec4( 0.0, 0.0, 0.0, opacity * ( 1.0 - getShadowMask() ) );\n}\n";
  5123  
  5124  	var shadow_vert = "#include <shadowmap_pars_vertex>\nvoid main() {\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n}\n";
  5125  
  5126  	var ShaderChunk = {
  5127  		alphamap_fragment: alphamap_fragment,
  5128  		alphamap_pars_fragment: alphamap_pars_fragment,
  5129  		alphatest_fragment: alphatest_fragment,
  5130  		aomap_fragment: aomap_fragment,
  5131  		aomap_pars_fragment: aomap_pars_fragment,
  5132  		begin_vertex: begin_vertex,
  5133  		beginnormal_vertex: beginnormal_vertex,
  5134  		bsdfs: bsdfs,
  5135  		bumpmap_pars_fragment: bumpmap_pars_fragment,
  5136  		clipping_planes_fragment: clipping_planes_fragment,
  5137  		clipping_planes_pars_fragment: clipping_planes_pars_fragment,
  5138  		clipping_planes_pars_vertex: clipping_planes_pars_vertex,
  5139  		clipping_planes_vertex: clipping_planes_vertex,
  5140  		color_fragment: color_fragment,
  5141  		color_pars_fragment: color_pars_fragment,
  5142  		color_pars_vertex: color_pars_vertex,
  5143  		color_vertex: color_vertex,
  5144  		common: common,
  5145  		cube_uv_reflection_fragment: cube_uv_reflection_fragment,
  5146  		defaultnormal_vertex: defaultnormal_vertex,
  5147  		displacementmap_pars_vertex: displacementmap_pars_vertex,
  5148  		displacementmap_vertex: displacementmap_vertex,
  5149  		emissivemap_fragment: emissivemap_fragment,
  5150  		emissivemap_pars_fragment: emissivemap_pars_fragment,
  5151  		encodings_fragment: encodings_fragment,
  5152  		encodings_pars_fragment: encodings_pars_fragment,
  5153  		envmap_fragment: envmap_fragment,
  5154  		envmap_pars_fragment: envmap_pars_fragment,
  5155  		envmap_pars_vertex: envmap_pars_vertex,
  5156  		envmap_vertex: envmap_vertex,
  5157  		fog_vertex: fog_vertex,
  5158  		fog_pars_vertex: fog_pars_vertex,
  5159  		fog_fragment: fog_fragment,
  5160  		fog_pars_fragment: fog_pars_fragment,
  5161  		gradientmap_pars_fragment: gradientmap_pars_fragment,
  5162  		lightmap_fragment: lightmap_fragment,
  5163  		lightmap_pars_fragment: lightmap_pars_fragment,
  5164  		lights_lambert_vertex: lights_lambert_vertex,
  5165  		lights_pars: lights_pars,
  5166  		lights_phong_fragment: lights_phong_fragment,
  5167  		lights_phong_pars_fragment: lights_phong_pars_fragment,
  5168  		lights_physical_fragment: lights_physical_fragment,
  5169  		lights_physical_pars_fragment: lights_physical_pars_fragment,
  5170  		lights_template: lights_template,
  5171  		logdepthbuf_fragment: logdepthbuf_fragment,
  5172  		logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
  5173  		logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
  5174  		logdepthbuf_vertex: logdepthbuf_vertex,
  5175  		map_fragment: map_fragment,
  5176  		map_pars_fragment: map_pars_fragment,
  5177  		map_particle_fragment: map_particle_fragment,
  5178  		map_particle_pars_fragment: map_particle_pars_fragment,
  5179  		metalnessmap_fragment: metalnessmap_fragment,
  5180  		metalnessmap_pars_fragment: metalnessmap_pars_fragment,
  5181  		morphnormal_vertex: morphnormal_vertex,
  5182  		morphtarget_pars_vertex: morphtarget_pars_vertex,
  5183  		morphtarget_vertex: morphtarget_vertex,
  5184  		normal_flip: normal_flip,
  5185  		normal_fragment: normal_fragment,
  5186  		normalmap_pars_fragment: normalmap_pars_fragment,
  5187  		packing: packing,
  5188  		premultiplied_alpha_fragment: premultiplied_alpha_fragment,
  5189  		project_vertex: project_vertex,
  5190  		roughnessmap_fragment: roughnessmap_fragment,
  5191  		roughnessmap_pars_fragment: roughnessmap_pars_fragment,
  5192  		shadowmap_pars_fragment: shadowmap_pars_fragment,
  5193  		shadowmap_pars_vertex: shadowmap_pars_vertex,
  5194  		shadowmap_vertex: shadowmap_vertex,
  5195  		shadowmask_pars_fragment: shadowmask_pars_fragment,
  5196  		skinbase_vertex: skinbase_vertex,
  5197  		skinning_pars_vertex: skinning_pars_vertex,
  5198  		skinning_vertex: skinning_vertex,
  5199  		skinnormal_vertex: skinnormal_vertex,
  5200  		specularmap_fragment: specularmap_fragment,
  5201  		specularmap_pars_fragment: specularmap_pars_fragment,
  5202  		tonemapping_fragment: tonemapping_fragment,
  5203  		tonemapping_pars_fragment: tonemapping_pars_fragment,
  5204  		uv_pars_fragment: uv_pars_fragment,
  5205  		uv_pars_vertex: uv_pars_vertex,
  5206  		uv_vertex: uv_vertex,
  5207  		uv2_pars_fragment: uv2_pars_fragment,
  5208  		uv2_pars_vertex: uv2_pars_vertex,
  5209  		uv2_vertex: uv2_vertex,
  5210  		worldpos_vertex: worldpos_vertex,
  5211  
  5212  		cube_frag: cube_frag,
  5213  		cube_vert: cube_vert,
  5214  		depth_frag: depth_frag,
  5215  		depth_vert: depth_vert,
  5216  		distanceRGBA_frag: distanceRGBA_frag,
  5217  		distanceRGBA_vert: distanceRGBA_vert,
  5218  		equirect_frag: equirect_frag,
  5219  		equirect_vert: equirect_vert,
  5220  		linedashed_frag: linedashed_frag,
  5221  		linedashed_vert: linedashed_vert,
  5222  		meshbasic_frag: meshbasic_frag,
  5223  		meshbasic_vert: meshbasic_vert,
  5224  		meshlambert_frag: meshlambert_frag,
  5225  		meshlambert_vert: meshlambert_vert,
  5226  		meshphong_frag: meshphong_frag,
  5227  		meshphong_vert: meshphong_vert,
  5228  		meshphysical_frag: meshphysical_frag,
  5229  		meshphysical_vert: meshphysical_vert,
  5230  		normal_frag: normal_frag,
  5231  		normal_vert: normal_vert,
  5232  		points_frag: points_frag,
  5233  		points_vert: points_vert,
  5234  		shadow_frag: shadow_frag,
  5235  		shadow_vert: shadow_vert
  5236  	};
  5237  
  5238  	/**
  5239  	 * @author mrdoob / http://mrdoob.com/
  5240  	 */
  5241  
  5242  	function Color( r, g, b ) {
  5243  
  5244  		if ( g === undefined && b === undefined ) {
  5245  
  5246  			// r is THREE.Color, hex or string
  5247  			return this.set( r );
  5248  
  5249  		}
  5250  
  5251  		return this.setRGB( r, g, b );
  5252  
  5253  	}
  5254  
  5255  	Color.prototype = {
  5256  
  5257  		constructor: Color,
  5258  
  5259  		isColor: true,
  5260  
  5261  		r: 1, g: 1, b: 1,
  5262  
  5263  		set: function ( value ) {
  5264  
  5265  			if ( value && value.isColor ) {
  5266  
  5267  				this.copy( value );
  5268  
  5269  			} else if ( typeof value === 'number' ) {
  5270  
  5271  				this.setHex( value );
  5272  
  5273  			} else if ( typeof value === 'string' ) {
  5274  
  5275  				this.setStyle( value );
  5276  
  5277  			}
  5278  
  5279  			return this;
  5280  
  5281  		},
  5282  
  5283  		setScalar: function ( scalar ) {
  5284  
  5285  			this.r = scalar;
  5286  			this.g = scalar;
  5287  			this.b = scalar;
  5288  
  5289  			return this;
  5290  
  5291  		},
  5292  
  5293  		setHex: function ( hex ) {
  5294  
  5295  			hex = Math.floor( hex );
  5296  
  5297  			this.r = ( hex >> 16 & 255 ) / 255;
  5298  			this.g = ( hex >> 8 & 255 ) / 255;
  5299  			this.b = ( hex & 255 ) / 255;
  5300  
  5301  			return this;
  5302  
  5303  		},
  5304  
  5305  		setRGB: function ( r, g, b ) {
  5306  
  5307  			this.r = r;
  5308  			this.g = g;
  5309  			this.b = b;
  5310  
  5311  			return this;
  5312  
  5313  		},
  5314  
  5315  		setHSL: function () {
  5316  
  5317  			function hue2rgb( p, q, t ) {
  5318  
  5319  				if ( t < 0 ) t += 1;
  5320  				if ( t > 1 ) t -= 1;
  5321  				if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
  5322  				if ( t < 1 / 2 ) return q;
  5323  				if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
  5324  				return p;
  5325  
  5326  			}
  5327  
  5328  			return function setHSL( h, s, l ) {
  5329  
  5330  				// h,s,l ranges are in 0.0 - 1.0
  5331  				h = _Math.euclideanModulo( h, 1 );
  5332  				s = _Math.clamp( s, 0, 1 );
  5333  				l = _Math.clamp( l, 0, 1 );
  5334  
  5335  				if ( s === 0 ) {
  5336  
  5337  					this.r = this.g = this.b = l;
  5338  
  5339  				} else {
  5340  
  5341  					var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
  5342  					var q = ( 2 * l ) - p;
  5343  
  5344  					this.r = hue2rgb( q, p, h + 1 / 3 );
  5345  					this.g = hue2rgb( q, p, h );
  5346  					this.b = hue2rgb( q, p, h - 1 / 3 );
  5347  
  5348  				}
  5349  
  5350  				return this;
  5351  
  5352  			};
  5353  
  5354  		}(),
  5355  
  5356  		setStyle: function ( style ) {
  5357  
  5358  			function handleAlpha( string ) {
  5359  
  5360  				if ( string === undefined ) return;
  5361  
  5362  				if ( parseFloat( string ) < 1 ) {
  5363  
  5364  					console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
  5365  
  5366  				}
  5367  
  5368  			}
  5369  
  5370  
  5371  			var m;
  5372  
  5373  			if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) {
  5374  
  5375  				// rgb / hsl
  5376  
  5377  				var color;
  5378  				var name = m[ 1 ];
  5379  				var components = m[ 2 ];
  5380  
  5381  				switch ( name ) {
  5382  
  5383  					case 'rgb':
  5384  					case 'rgba':
  5385  
  5386  						if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
  5387  
  5388  							// rgb(255,0,0) rgba(255,0,0,0.5)
  5389  							this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
  5390  							this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
  5391  							this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
  5392  
  5393  							handleAlpha( color[ 5 ] );
  5394  
  5395  							return this;
  5396  
  5397  						}
  5398  
  5399  						if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
  5400  
  5401  							// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
  5402  							this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
  5403  							this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
  5404  							this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
  5405  
  5406  							handleAlpha( color[ 5 ] );
  5407  
  5408  							return this;
  5409  
  5410  						}
  5411  
  5412  						break;
  5413  
  5414  					case 'hsl':
  5415  					case 'hsla':
  5416  
  5417  						if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
  5418  
  5419  							// hsl(120,50%,50%) hsla(120,50%,50%,0.5)
  5420  							var h = parseFloat( color[ 1 ] ) / 360;
  5421  							var s = parseInt( color[ 2 ], 10 ) / 100;
  5422  							var l = parseInt( color[ 3 ], 10 ) / 100;
  5423  
  5424  							handleAlpha( color[ 5 ] );
  5425  
  5426  							return this.setHSL( h, s, l );
  5427  
  5428  						}
  5429  
  5430  						break;
  5431  
  5432  				}
  5433  
  5434  			} else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) {
  5435  
  5436  				// hex color
  5437  
  5438  				var hex = m[ 1 ];
  5439  				var size = hex.length;
  5440  
  5441  				if ( size === 3 ) {
  5442  
  5443  					// #ff0
  5444  					this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
  5445  					this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
  5446  					this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
  5447  
  5448  					return this;
  5449  
  5450  				} else if ( size === 6 ) {
  5451  
  5452  					// #ff0000
  5453  					this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
  5454  					this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
  5455  					this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
  5456  
  5457  					return this;
  5458  
  5459  				}
  5460  
  5461  			}
  5462  
  5463  			if ( style && style.length > 0 ) {
  5464  
  5465  				// color keywords
  5466  				var hex = ColorKeywords[ style ];
  5467  
  5468  				if ( hex !== undefined ) {
  5469  
  5470  					// red
  5471  					this.setHex( hex );
  5472  
  5473  				} else {
  5474  
  5475  					// unknown color
  5476  					console.warn( 'THREE.Color: Unknown color ' + style );
  5477  
  5478  				}
  5479  
  5480  			}
  5481  
  5482  			return this;
  5483  
  5484  		},
  5485  
  5486  		clone: function () {
  5487  
  5488  			return new this.constructor( this.r, this.g, this.b );
  5489  
  5490  		},
  5491  
  5492  		copy: function ( color ) {
  5493  
  5494  			this.r = color.r;
  5495  			this.g = color.g;
  5496  			this.b = color.b;
  5497  
  5498  			return this;
  5499  
  5500  		},
  5501  
  5502  		copyGammaToLinear: function ( color, gammaFactor ) {
  5503  
  5504  			if ( gammaFactor === undefined ) gammaFactor = 2.0;
  5505  
  5506  			this.r = Math.pow( color.r, gammaFactor );
  5507  			this.g = Math.pow( color.g, gammaFactor );
  5508  			this.b = Math.pow( color.b, gammaFactor );
  5509  
  5510  			return this;
  5511  
  5512  		},
  5513  
  5514  		copyLinearToGamma: function ( color, gammaFactor ) {
  5515  
  5516  			if ( gammaFactor === undefined ) gammaFactor = 2.0;
  5517  
  5518  			var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;
  5519  
  5520  			this.r = Math.pow( color.r, safeInverse );
  5521  			this.g = Math.pow( color.g, safeInverse );
  5522  			this.b = Math.pow( color.b, safeInverse );
  5523  
  5524  			return this;
  5525  
  5526  		},
  5527  
  5528  		convertGammaToLinear: function () {
  5529  
  5530  			var r = this.r, g = this.g, b = this.b;
  5531  
  5532  			this.r = r * r;
  5533  			this.g = g * g;
  5534  			this.b = b * b;
  5535  
  5536  			return this;
  5537  
  5538  		},
  5539  
  5540  		convertLinearToGamma: function () {
  5541  
  5542  			this.r = Math.sqrt( this.r );
  5543  			this.g = Math.sqrt( this.g );
  5544  			this.b = Math.sqrt( this.b );
  5545  
  5546  			return this;
  5547  
  5548  		},
  5549  
  5550  		getHex: function () {
  5551  
  5552  			return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;
  5553  
  5554  		},
  5555  
  5556  		getHexString: function () {
  5557  
  5558  			return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
  5559  
  5560  		},
  5561  
  5562  		getHSL: function ( optionalTarget ) {
  5563  
  5564  			// h,s,l ranges are in 0.0 - 1.0
  5565  
  5566  			var hsl = optionalTarget || { h: 0, s: 0, l: 0 };
  5567  
  5568  			var r = this.r, g = this.g, b = this.b;
  5569  
  5570  			var max = Math.max( r, g, b );
  5571  			var min = Math.min( r, g, b );
  5572  
  5573  			var hue, saturation;
  5574  			var lightness = ( min + max ) / 2.0;
  5575  
  5576  			if ( min === max ) {
  5577  
  5578  				hue = 0;
  5579  				saturation = 0;
  5580  
  5581  			} else {
  5582  
  5583  				var delta = max - min;
  5584  
  5585  				saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
  5586  
  5587  				switch ( max ) {
  5588  
  5589  					case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
  5590  					case g: hue = ( b - r ) / delta + 2; break;
  5591  					case b: hue = ( r - g ) / delta + 4; break;
  5592  
  5593  				}
  5594  
  5595  				hue /= 6;
  5596  
  5597  			}
  5598  
  5599  			hsl.h = hue;
  5600  			hsl.s = saturation;
  5601  			hsl.l = lightness;
  5602  
  5603  			return hsl;
  5604  
  5605  		},
  5606  
  5607  		getStyle: function () {
  5608  
  5609  			return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
  5610  
  5611  		},
  5612  
  5613  		offsetHSL: function ( h, s, l ) {
  5614  
  5615  			var hsl = this.getHSL();
  5616  
  5617  			hsl.h += h; hsl.s += s; hsl.l += l;
  5618  
  5619  			this.setHSL( hsl.h, hsl.s, hsl.l );
  5620  
  5621  			return this;
  5622  
  5623  		},
  5624  
  5625  		add: function ( color ) {
  5626  
  5627  			this.r += color.r;
  5628  			this.g += color.g;
  5629  			this.b += color.b;
  5630  
  5631  			return this;
  5632  
  5633  		},
  5634  
  5635  		addColors: function ( color1, color2 ) {
  5636  
  5637  			this.r = color1.r + color2.r;
  5638  			this.g = color1.g + color2.g;
  5639  			this.b = color1.b + color2.b;
  5640  
  5641  			return this;
  5642  
  5643  		},
  5644  
  5645  		addScalar: function ( s ) {
  5646  
  5647  			this.r += s;
  5648  			this.g += s;
  5649  			this.b += s;
  5650  
  5651  			return this;
  5652  
  5653  		},
  5654  
  5655  		sub: function( color ) {
  5656  
  5657  			this.r = Math.max( 0, this.r - color.r );
  5658  			this.g = Math.max( 0, this.g - color.g );
  5659  			this.b = Math.max( 0, this.b - color.b );
  5660  
  5661  			return this;
  5662  
  5663  		},
  5664  
  5665  		multiply: function ( color ) {
  5666  
  5667  			this.r *= color.r;
  5668  			this.g *= color.g;
  5669  			this.b *= color.b;
  5670  
  5671  			return this;
  5672  
  5673  		},
  5674  
  5675  		multiplyScalar: function ( s ) {
  5676  
  5677  			this.r *= s;
  5678  			this.g *= s;
  5679  			this.b *= s;
  5680  
  5681  			return this;
  5682  
  5683  		},
  5684  
  5685  		lerp: function ( color, alpha ) {
  5686  
  5687  			this.r += ( color.r - this.r ) * alpha;
  5688  			this.g += ( color.g - this.g ) * alpha;
  5689  			this.b += ( color.b - this.b ) * alpha;
  5690  
  5691  			return this;
  5692  
  5693  		},
  5694  
  5695  		equals: function ( c ) {
  5696  
  5697  			return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
  5698  
  5699  		},
  5700  
  5701  		fromArray: function ( array, offset ) {
  5702  
  5703  			if ( offset === undefined ) offset = 0;
  5704  
  5705  			this.r = array[ offset ];
  5706  			this.g = array[ offset + 1 ];
  5707  			this.b = array[ offset + 2 ];
  5708  
  5709  			return this;
  5710  
  5711  		},
  5712  
  5713  		toArray: function ( array, offset ) {
  5714  
  5715  			if ( array === undefined ) array = [];
  5716  			if ( offset === undefined ) offset = 0;
  5717  
  5718  			array[ offset ] = this.r;
  5719  			array[ offset + 1 ] = this.g;
  5720  			array[ offset + 2 ] = this.b;
  5721  
  5722  			return array;
  5723  
  5724  		},
  5725  
  5726  		toJSON: function () {
  5727  
  5728  			return this.getHex();
  5729  
  5730  		}
  5731  
  5732  	};
  5733  
  5734  	var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
  5735  	'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
  5736  	'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
  5737  	'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
  5738  	'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
  5739  	'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
  5740  	'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
  5741  	'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
  5742  	'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
  5743  	'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
  5744  	'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
  5745  	'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
  5746  	'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
  5747  	'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
  5748  	'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
  5749  	'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
  5750  	'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
  5751  	'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
  5752  	'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
  5753  	'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
  5754  	'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
  5755  	'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
  5756  	'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
  5757  	'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
  5758  
  5759  	/**
  5760  	 * @author alteredq / http://alteredqualia.com/
  5761  	 */
  5762  
  5763  	function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
  5764  
  5765  		Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
  5766  
  5767  		this.image = { data: data, width: width, height: height };
  5768  
  5769  		this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
  5770  		this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
  5771  
  5772  		this.generateMipmaps  = false;
  5773  		this.flipY = false;
  5774  		this.unpackAlignment = 1;
  5775  
  5776  	}
  5777  
  5778  	DataTexture.prototype = Object.create( Texture.prototype );
  5779  	DataTexture.prototype.constructor = DataTexture;
  5780  
  5781  	DataTexture.prototype.isDataTexture = true;
  5782  
  5783  	/**
  5784  	 * Uniforms library for shared webgl shaders
  5785  	 */
  5786  
  5787  	var UniformsLib = {
  5788  
  5789  		common: {
  5790  
  5791  			diffuse: { value: new Color( 0xeeeeee ) },
  5792  			opacity: { value: 1.0 },
  5793  
  5794  			map: { value: null },
  5795  			offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) },
  5796  
  5797  			specularMap: { value: null },
  5798  			alphaMap: { value: null },
  5799  
  5800  			envMap: { value: null },
  5801  			flipEnvMap: { value: - 1 },
  5802  			reflectivity: { value: 1.0 },
  5803  			refractionRatio: { value: 0.98 }
  5804  
  5805  		},
  5806  
  5807  		aomap: {
  5808  
  5809  			aoMap: { value: null },
  5810  			aoMapIntensity: { value: 1 }
  5811  
  5812  		},
  5813  
  5814  		lightmap: {
  5815  
  5816  			lightMap: { value: null },
  5817  			lightMapIntensity: { value: 1 }
  5818  
  5819  		},
  5820  
  5821  		emissivemap: {
  5822  
  5823  			emissiveMap: { value: null }
  5824  
  5825  		},
  5826  
  5827  		bumpmap: {
  5828  
  5829  			bumpMap: { value: null },
  5830  			bumpScale: { value: 1 }
  5831  
  5832  		},
  5833  
  5834  		normalmap: {
  5835  
  5836  			normalMap: { value: null },
  5837  			normalScale: { value: new Vector2( 1, 1 ) }
  5838  
  5839  		},
  5840  
  5841  		displacementmap: {
  5842  
  5843  			displacementMap: { value: null },
  5844  			displacementScale: { value: 1 },
  5845  			displacementBias: { value: 0 }
  5846  
  5847  		},
  5848  
  5849  		roughnessmap: {
  5850  
  5851  			roughnessMap: { value: null }
  5852  
  5853  		},
  5854  
  5855  		metalnessmap: {
  5856  
  5857  			metalnessMap: { value: null }
  5858  
  5859  		},
  5860  
  5861  		gradientmap: {
  5862  
  5863  			gradientMap: { value: null }
  5864  
  5865  		},
  5866  
  5867  		fog: {
  5868  
  5869  			fogDensity: { value: 0.00025 },
  5870  			fogNear: { value: 1 },
  5871  			fogFar: { value: 2000 },
  5872  			fogColor: { value: new Color( 0xffffff ) }
  5873  
  5874  		},
  5875  
  5876  		lights: {
  5877  
  5878  			ambientLightColor: { value: [] },
  5879  
  5880  			directionalLights: { value: [], properties: {
  5881  				direction: {},
  5882  				color: {},
  5883  
  5884  				shadow: {},
  5885  				shadowBias: {},
  5886  				shadowRadius: {},
  5887  				shadowMapSize: {}
  5888  			} },
  5889  
  5890  			directionalShadowMap: { value: [] },
  5891  			directionalShadowMatrix: { value: [] },
  5892  
  5893  			spotLights: { value: [], properties: {
  5894  				color: {},
  5895  				position: {},
  5896  				direction: {},
  5897  				distance: {},
  5898  				coneCos: {},
  5899  				penumbraCos: {},
  5900  				decay: {},
  5901  
  5902  				shadow: {},
  5903  				shadowBias: {},
  5904  				shadowRadius: {},
  5905  				shadowMapSize: {}
  5906  			} },
  5907  
  5908  			spotShadowMap: { value: [] },
  5909  			spotShadowMatrix: { value: [] },
  5910  
  5911  			pointLights: { value: [], properties: {
  5912  				color: {},
  5913  				position: {},
  5914  				decay: {},
  5915  				distance: {},
  5916  
  5917  				shadow: {},
  5918  				shadowBias: {},
  5919  				shadowRadius: {},
  5920  				shadowMapSize: {}
  5921  			} },
  5922  
  5923  			pointShadowMap: { value: [] },
  5924  			pointShadowMatrix: { value: [] },
  5925  
  5926  			hemisphereLights: { value: [], properties: {
  5927  				direction: {},
  5928  				skyColor: {},
  5929  				groundColor: {}
  5930  			} },
  5931  
  5932  			// TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
  5933  			rectAreaLights: { value: [], properties: {
  5934  				color: {},
  5935  				position: {},
  5936  				width: {},
  5937  				height: {}
  5938  			} }
  5939  
  5940  		},
  5941  
  5942  		points: {
  5943  
  5944  			diffuse: { value: new Color( 0xeeeeee ) },
  5945  			opacity: { value: 1.0 },
  5946  			size: { value: 1.0 },
  5947  			scale: { value: 1.0 },
  5948  			map: { value: null },
  5949  			offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) }
  5950  
  5951  		}
  5952  
  5953  	};
  5954  
  5955  	/**
  5956  	 * @author alteredq / http://alteredqualia.com/
  5957  	 * @author mrdoob / http://mrdoob.com/
  5958  	 * @author mikael emtinger / http://gomo.se/
  5959  	 */
  5960  
  5961  	var ShaderLib = {
  5962  
  5963  		basic: {
  5964  
  5965  			uniforms: UniformsUtils.merge( [
  5966  				UniformsLib.common,
  5967  				UniformsLib.aomap,
  5968  				UniformsLib.lightmap,
  5969  				UniformsLib.fog
  5970  			] ),
  5971  
  5972  			vertexShader: ShaderChunk.meshbasic_vert,
  5973  			fragmentShader: ShaderChunk.meshbasic_frag
  5974  
  5975  		},
  5976  
  5977  		lambert: {
  5978  
  5979  			uniforms: UniformsUtils.merge( [
  5980  				UniformsLib.common,
  5981  				UniformsLib.aomap,
  5982  				UniformsLib.lightmap,
  5983  				UniformsLib.emissivemap,
  5984  				UniformsLib.fog,
  5985  				UniformsLib.lights,
  5986  				{
  5987  					emissive: { value: new Color( 0x000000 ) }
  5988  				}
  5989  			] ),
  5990  
  5991  			vertexShader: ShaderChunk.meshlambert_vert,
  5992  			fragmentShader: ShaderChunk.meshlambert_frag
  5993  
  5994  		},
  5995  
  5996  		phong: {
  5997  
  5998  			uniforms: UniformsUtils.merge( [
  5999  				UniformsLib.common,
  6000  				UniformsLib.aomap,
  6001  				UniformsLib.lightmap,
  6002  				UniformsLib.emissivemap,
  6003  				UniformsLib.bumpmap,
  6004  				UniformsLib.normalmap,
  6005  				UniformsLib.displacementmap,
  6006  				UniformsLib.gradientmap,
  6007  				UniformsLib.fog,
  6008  				UniformsLib.lights,
  6009  				{
  6010  					emissive: { value: new Color( 0x000000 ) },
  6011  					specular: { value: new Color( 0x111111 ) },
  6012  					shininess: { value: 30 }
  6013  				}
  6014  			] ),
  6015  
  6016  			vertexShader: ShaderChunk.meshphong_vert,
  6017  			fragmentShader: ShaderChunk.meshphong_frag
  6018  
  6019  		},
  6020  
  6021  		standard: {
  6022  
  6023  			uniforms: UniformsUtils.merge( [
  6024  				UniformsLib.common,
  6025  				UniformsLib.aomap,
  6026  				UniformsLib.lightmap,
  6027  				UniformsLib.emissivemap,
  6028  				UniformsLib.bumpmap,
  6029  				UniformsLib.normalmap,
  6030  				UniformsLib.displacementmap,
  6031  				UniformsLib.roughnessmap,
  6032  				UniformsLib.metalnessmap,
  6033  				UniformsLib.fog,
  6034  				UniformsLib.lights,
  6035  				{
  6036  					emissive: { value: new Color( 0x000000 ) },
  6037  					roughness: { value: 0.5 },
  6038  					metalness: { value: 0 },
  6039  					envMapIntensity: { value: 1 } // temporary
  6040  				}
  6041  			] ),
  6042  
  6043  			vertexShader: ShaderChunk.meshphysical_vert,
  6044  			fragmentShader: ShaderChunk.meshphysical_frag
  6045  
  6046  		},
  6047  
  6048  		points: {
  6049  
  6050  			uniforms: UniformsUtils.merge( [
  6051  				UniformsLib.points,
  6052  				UniformsLib.fog
  6053  			] ),
  6054  
  6055  			vertexShader: ShaderChunk.points_vert,
  6056  			fragmentShader: ShaderChunk.points_frag
  6057  
  6058  		},
  6059  
  6060  		dashed: {
  6061  
  6062  			uniforms: UniformsUtils.merge( [
  6063  				UniformsLib.common,
  6064  				UniformsLib.fog,
  6065  				{
  6066  					scale: { value: 1 },
  6067  					dashSize: { value: 1 },
  6068  					totalSize: { value: 2 }
  6069  				}
  6070  			] ),
  6071  
  6072  			vertexShader: ShaderChunk.linedashed_vert,
  6073  			fragmentShader: ShaderChunk.linedashed_frag
  6074  
  6075  		},
  6076  
  6077  		depth: {
  6078  
  6079  			uniforms: UniformsUtils.merge( [
  6080  				UniformsLib.common,
  6081  				UniformsLib.displacementmap
  6082  			] ),
  6083  
  6084  			vertexShader: ShaderChunk.depth_vert,
  6085  			fragmentShader: ShaderChunk.depth_frag
  6086  
  6087  		},
  6088  
  6089  		normal: {
  6090  
  6091  			uniforms: UniformsUtils.merge( [
  6092  				UniformsLib.common,
  6093  				UniformsLib.bumpmap,
  6094  				UniformsLib.normalmap,
  6095  				UniformsLib.displacementmap,
  6096  				{
  6097  					opacity: { value: 1.0 }
  6098  				}
  6099  			] ),
  6100  
  6101  			vertexShader: ShaderChunk.normal_vert,
  6102  			fragmentShader: ShaderChunk.normal_frag
  6103  
  6104  		},
  6105  
  6106  		/* -------------------------------------------------------------------------
  6107  		//	Cube map shader
  6108  		 ------------------------------------------------------------------------- */
  6109  
  6110  		cube: {
  6111  
  6112  			uniforms: {
  6113  				tCube: { value: null },
  6114  				tFlip: { value: - 1 },
  6115  				opacity: { value: 1.0 }
  6116  			},
  6117  
  6118  			vertexShader: ShaderChunk.cube_vert,
  6119  			fragmentShader: ShaderChunk.cube_frag
  6120  
  6121  		},
  6122  
  6123  		/* -------------------------------------------------------------------------
  6124  		//	Cube map shader
  6125  		 ------------------------------------------------------------------------- */
  6126  
  6127  		equirect: {
  6128  
  6129  			uniforms: {
  6130  				tEquirect: { value: null },
  6131  				tFlip: { value: - 1 }
  6132  			},
  6133  
  6134  			vertexShader: ShaderChunk.equirect_vert,
  6135  			fragmentShader: ShaderChunk.equirect_frag
  6136  
  6137  		},
  6138  
  6139  		distanceRGBA: {
  6140  
  6141  			uniforms: {
  6142  				lightPos: { value: new Vector3() }
  6143  			},
  6144  
  6145  			vertexShader: ShaderChunk.distanceRGBA_vert,
  6146  			fragmentShader: ShaderChunk.distanceRGBA_frag
  6147  
  6148  		}
  6149  
  6150  	};
  6151  
  6152  	ShaderLib.physical = {
  6153  
  6154  		uniforms: UniformsUtils.merge( [
  6155  			ShaderLib.standard.uniforms,
  6156  			{
  6157  				clearCoat: { value: 0 },
  6158  				clearCoatRoughness: { value: 0 }
  6159  			}
  6160  		] ),
  6161  
  6162  		vertexShader: ShaderChunk.meshphysical_vert,
  6163  		fragmentShader: ShaderChunk.meshphysical_frag
  6164  
  6165  	};
  6166  
  6167  	/**
  6168  	 * @author bhouston / http://clara.io
  6169  	 */
  6170  
  6171  	function Box2( min, max ) {
  6172  
  6173  		this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity );
  6174  		this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity );
  6175  
  6176  	}
  6177  
  6178  	Box2.prototype = {
  6179  
  6180  		constructor: Box2,
  6181  
  6182  		set: function ( min, max ) {
  6183  
  6184  			this.min.copy( min );
  6185  			this.max.copy( max );
  6186  
  6187  			return this;
  6188  
  6189  		},
  6190  
  6191  		setFromPoints: function ( points ) {
  6192  
  6193  			this.makeEmpty();
  6194  
  6195  			for ( var i = 0, il = points.length; i < il; i ++ ) {
  6196  
  6197  				this.expandByPoint( points[ i ] );
  6198  
  6199  			}
  6200  
  6201  			return this;
  6202  
  6203  		},
  6204  
  6205  		setFromCenterAndSize: function () {
  6206  
  6207  			var v1 = new Vector2();
  6208  
  6209  			return function setFromCenterAndSize( center, size ) {
  6210  
  6211  				var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
  6212  				this.min.copy( center ).sub( halfSize );
  6213  				this.max.copy( center ).add( halfSize );
  6214  
  6215  				return this;
  6216  
  6217  			};
  6218  
  6219  		}(),
  6220  
  6221  		clone: function () {
  6222  
  6223  			return new this.constructor().copy( this );
  6224  
  6225  		},
  6226  
  6227  		copy: function ( box ) {
  6228  
  6229  			this.min.copy( box.min );
  6230  			this.max.copy( box.max );
  6231  
  6232  			return this;
  6233  
  6234  		},
  6235  
  6236  		makeEmpty: function () {
  6237  
  6238  			this.min.x = this.min.y = + Infinity;
  6239  			this.max.x = this.max.y = - Infinity;
  6240  
  6241  			return this;
  6242  
  6243  		},
  6244  
  6245  		isEmpty: function () {
  6246  
  6247  			// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
  6248  
  6249  			return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
  6250  
  6251  		},
  6252  
  6253  		getCenter: function ( optionalTarget ) {
  6254  
  6255  			var result = optionalTarget || new Vector2();
  6256  			return this.isEmpty() ? result.set( 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
  6257  
  6258  		},
  6259  
  6260  		getSize: function ( optionalTarget ) {
  6261  
  6262  			var result = optionalTarget || new Vector2();
  6263  			return this.isEmpty() ? result.set( 0, 0 ) : result.subVectors( this.max, this.min );
  6264  
  6265  		},
  6266  
  6267  		expandByPoint: function ( point ) {
  6268  
  6269  			this.min.min( point );
  6270  			this.max.max( point );
  6271  
  6272  			return this;
  6273  
  6274  		},
  6275  
  6276  		expandByVector: function ( vector ) {
  6277  
  6278  			this.min.sub( vector );
  6279  			this.max.add( vector );
  6280  
  6281  			return this;
  6282  
  6283  		},
  6284  
  6285  		expandByScalar: function ( scalar ) {
  6286  
  6287  			this.min.addScalar( - scalar );
  6288  			this.max.addScalar( scalar );
  6289  
  6290  			return this;
  6291  
  6292  		},
  6293  
  6294  		containsPoint: function ( point ) {
  6295  
  6296  			return point.x < this.min.x || point.x > this.max.x ||
  6297  				point.y < this.min.y || point.y > this.max.y ? false : true;
  6298  
  6299  		},
  6300  
  6301  		containsBox: function ( box ) {
  6302  
  6303  			return this.min.x <= box.min.x && box.max.x <= this.max.x &&
  6304  				this.min.y <= box.min.y && box.max.y <= this.max.y;
  6305  
  6306  		},
  6307  
  6308  		getParameter: function ( point, optionalTarget ) {
  6309  
  6310  			// This can potentially have a divide by zero if the box
  6311  			// has a size dimension of 0.
  6312  
  6313  			var result = optionalTarget || new Vector2();
  6314  
  6315  			return result.set(
  6316  				( point.x - this.min.x ) / ( this.max.x - this.min.x ),
  6317  				( point.y - this.min.y ) / ( this.max.y - this.min.y )
  6318  			);
  6319  
  6320  		},
  6321  
  6322  		intersectsBox: function ( box ) {
  6323  
  6324  			// using 6 splitting planes to rule out intersections.
  6325  			return box.max.x < this.min.x || box.min.x > this.max.x ||
  6326  				box.max.y < this.min.y || box.min.y > this.max.y ? false : true;
  6327  
  6328  		},
  6329  
  6330  		clampPoint: function ( point, optionalTarget ) {
  6331  
  6332  			var result = optionalTarget || new Vector2();
  6333  			return result.copy( point ).clamp( this.min, this.max );
  6334  
  6335  		},
  6336  
  6337  		distanceToPoint: function () {
  6338  
  6339  			var v1 = new Vector2();
  6340  
  6341  			return function distanceToPoint( point ) {
  6342  
  6343  				var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
  6344  				return clampedPoint.sub( point ).length();
  6345  
  6346  			};
  6347  
  6348  		}(),
  6349  
  6350  		intersect: function ( box ) {
  6351  
  6352  			this.min.max( box.min );
  6353  			this.max.min( box.max );
  6354  
  6355  			return this;
  6356  
  6357  		},
  6358  
  6359  		union: function ( box ) {
  6360  
  6361  			this.min.min( box.min );
  6362  			this.max.max( box.max );
  6363  
  6364  			return this;
  6365  
  6366  		},
  6367  
  6368  		translate: function ( offset ) {
  6369  
  6370  			this.min.add( offset );
  6371  			this.max.add( offset );
  6372  
  6373  			return this;
  6374  
  6375  		},
  6376  
  6377  		equals: function ( box ) {
  6378  
  6379  			return box.min.equals( this.min ) && box.max.equals( this.max );
  6380  
  6381  		}
  6382  
  6383  	};
  6384  
  6385  	/**
  6386  	 * @author mikael emtinger / http://gomo.se/
  6387  	 * @author alteredq / http://alteredqualia.com/
  6388  	 */
  6389  
  6390  	function LensFlarePlugin( renderer, flares ) {
  6391  
  6392  		var gl = renderer.context;
  6393  		var state = renderer.state;
  6394  
  6395  		var vertexBuffer, elementBuffer;
  6396  		var shader, program, attributes, uniforms;
  6397  
  6398  		var tempTexture, occlusionTexture;
  6399  
  6400  		function init() {
  6401  
  6402  			var vertices = new Float32Array( [
  6403  				- 1, - 1,  0, 0,
  6404  				 1, - 1,  1, 0,
  6405  				 1,  1,  1, 1,
  6406  				- 1,  1,  0, 1
  6407  			] );
  6408  
  6409  			var faces = new Uint16Array( [
  6410  				0, 1, 2,
  6411  				0, 2, 3
  6412  			] );
  6413  
  6414  			// buffers
  6415  
  6416  			vertexBuffer     = gl.createBuffer();
  6417  			elementBuffer    = gl.createBuffer();
  6418  
  6419  			gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
  6420  			gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );
  6421  
  6422  			gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
  6423  			gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );
  6424  
  6425  			// textures
  6426  
  6427  			tempTexture      = gl.createTexture();
  6428  			occlusionTexture = gl.createTexture();
  6429  
  6430  			state.bindTexture( gl.TEXTURE_2D, tempTexture );
  6431  			gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, 16, 16, 0, gl.RGB, gl.UNSIGNED_BYTE, null );
  6432  			gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
  6433  			gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
  6434  			gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
  6435  			gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
  6436  
  6437  			state.bindTexture( gl.TEXTURE_2D, occlusionTexture );
  6438  			gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );
  6439  			gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
  6440  			gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
  6441  			gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
  6442  			gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
  6443  
  6444  			shader = {
  6445  
  6446  				vertexShader: [
  6447  
  6448  					"uniform lowp int renderType;",
  6449  
  6450  					"uniform vec3 screenPosition;",
  6451  					"uniform vec2 scale;",
  6452  					"uniform float rotation;",
  6453  
  6454  					"uniform sampler2D occlusionMap;",
  6455  
  6456  					"attribute vec2 position;",
  6457  					"attribute vec2 uv;",
  6458  
  6459  					"varying vec2 vUV;",
  6460  					"varying float vVisibility;",
  6461  
  6462  					"void main() {",
  6463  
  6464  						"vUV = uv;",
  6465  
  6466  						"vec2 pos = position;",
  6467  
  6468  						"if ( renderType == 2 ) {",
  6469  
  6470  							"vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );",
  6471  							"visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );",
  6472  							"visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );",
  6473  							"visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );",
  6474  							"visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );",
  6475  							"visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );",
  6476  							"visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );",
  6477  							"visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );",
  6478  							"visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );",
  6479  
  6480  							"vVisibility =        visibility.r / 9.0;",
  6481  							"vVisibility *= 1.0 - visibility.g / 9.0;",
  6482  							"vVisibility *=       visibility.b / 9.0;",
  6483  							"vVisibility *= 1.0 - visibility.a / 9.0;",
  6484  
  6485  							"pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;",
  6486  							"pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;",
  6487  
  6488  						"}",
  6489  
  6490  						"gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );",
  6491  
  6492  					"}"
  6493  
  6494  				].join( "\n" ),
  6495  
  6496  				fragmentShader: [
  6497  
  6498  					"uniform lowp int renderType;",
  6499  
  6500  					"uniform sampler2D map;",
  6501  					"uniform float opacity;",
  6502  					"uniform vec3 color;",
  6503  
  6504  					"varying vec2 vUV;",
  6505  					"varying float vVisibility;",
  6506  
  6507  					"void main() {",
  6508  
  6509  						// pink square
  6510  
  6511  						"if ( renderType == 0 ) {",
  6512  
  6513  							"gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );",
  6514  
  6515  						// restore
  6516  
  6517  						"} else if ( renderType == 1 ) {",
  6518  
  6519  							"gl_FragColor = texture2D( map, vUV );",
  6520  
  6521  						// flare
  6522  
  6523  						"} else {",
  6524  
  6525  							"vec4 texture = texture2D( map, vUV );",
  6526  							"texture.a *= opacity * vVisibility;",
  6527  							"gl_FragColor = texture;",
  6528  							"gl_FragColor.rgb *= color;",
  6529  
  6530  						"}",
  6531  
  6532  					"}"
  6533  
  6534  				].join( "\n" )
  6535  
  6536  			};
  6537  
  6538  			program = createProgram( shader );
  6539  
  6540  			attributes = {
  6541  				vertex: gl.getAttribLocation ( program, "position" ),
  6542  				uv:     gl.getAttribLocation ( program, "uv" )
  6543  			};
  6544  
  6545  			uniforms = {
  6546  				renderType:     gl.getUniformLocation( program, "renderType" ),
  6547  				map:            gl.getUniformLocation( program, "map" ),
  6548  				occlusionMap:   gl.getUniformLocation( program, "occlusionMap" ),
  6549  				opacity:        gl.getUniformLocation( program, "opacity" ),
  6550  				color:          gl.getUniformLocation( program, "color" ),
  6551  				scale:          gl.getUniformLocation( program, "scale" ),
  6552  				rotation:       gl.getUniformLocation( program, "rotation" ),
  6553  				screenPosition: gl.getUniformLocation( program, "screenPosition" )
  6554  			};
  6555  
  6556  		}
  6557  
  6558  		/*
  6559  		 * Render lens flares
  6560  		 * Method: renders 16x16 0xff00ff-colored points scattered over the light source area,
  6561  		 *         reads these back and calculates occlusion.
  6562  		 */
  6563  
  6564  		this.render = function ( scene, camera, viewport ) {
  6565  
  6566  			if ( flares.length === 0 ) return;
  6567  
  6568  			var tempPosition = new Vector3();
  6569  
  6570  			var invAspect = viewport.w / viewport.z,
  6571  				halfViewportWidth = viewport.z * 0.5,
  6572  				halfViewportHeight = viewport.w * 0.5;
  6573  
  6574  			var size = 16 / viewport.w,
  6575  				scale = new Vector2( size * invAspect, size );
  6576  
  6577  			var screenPosition = new Vector3( 1, 1, 0 ),
  6578  				screenPositionPixels = new Vector2( 1, 1 );
  6579  
  6580  			var validArea = new Box2();
  6581  
  6582  			validArea.min.set( viewport.x, viewport.y );
  6583  			validArea.max.set( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) );
  6584  
  6585  			if ( program === undefined ) {
  6586  
  6587  				init();
  6588  
  6589  			}
  6590  
  6591  			gl.useProgram( program );
  6592  
  6593  			state.initAttributes();
  6594  			state.enableAttribute( attributes.vertex );
  6595  			state.enableAttribute( attributes.uv );
  6596  			state.disableUnusedAttributes();
  6597  
  6598  			// loop through all lens flares to update their occlusion and positions
  6599  			// setup gl and common used attribs/uniforms
  6600  
  6601  			gl.uniform1i( uniforms.occlusionMap, 0 );
  6602  			gl.uniform1i( uniforms.map, 1 );
  6603  
  6604  			gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
  6605  			gl.vertexAttribPointer( attributes.vertex, 2, gl.FLOAT, false, 2 * 8, 0 );
  6606  			gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );
  6607  
  6608  			gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
  6609  
  6610  			state.disable( gl.CULL_FACE );
  6611  			state.setDepthWrite( false );
  6612  
  6613  			for ( var i = 0, l = flares.length; i < l; i ++ ) {
  6614  
  6615  				size = 16 / viewport.w;
  6616  				scale.set( size * invAspect, size );
  6617  
  6618  				// calc object screen position
  6619  
  6620  				var flare = flares[ i ];
  6621  
  6622  				tempPosition.set( flare.matrixWorld.elements[ 12 ], flare.matrixWorld.elements[ 13 ], flare.matrixWorld.elements[ 14 ] );
  6623  
  6624  				tempPosition.applyMatrix4( camera.matrixWorldInverse );
  6625  				tempPosition.applyMatrix4( camera.projectionMatrix );
  6626  
  6627  				// setup arrays for gl programs
  6628  
  6629  				screenPosition.copy( tempPosition );
  6630  
  6631  				// horizontal and vertical coordinate of the lower left corner of the pixels to copy
  6632  
  6633  				screenPositionPixels.x = viewport.x + ( screenPosition.x * halfViewportWidth ) + halfViewportWidth - 8;
  6634  				screenPositionPixels.y = viewport.y + ( screenPosition.y * halfViewportHeight ) + halfViewportHeight - 8;
  6635  
  6636  				// screen cull
  6637  
  6638  				if ( validArea.containsPoint( screenPositionPixels ) === true ) {
  6639  
  6640  					// save current RGB to temp texture
  6641  
  6642  					state.activeTexture( gl.TEXTURE0 );
  6643  					state.bindTexture( gl.TEXTURE_2D, null );
  6644  					state.activeTexture( gl.TEXTURE1 );
  6645  					state.bindTexture( gl.TEXTURE_2D, tempTexture );
  6646  					gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 );
  6647  
  6648  
  6649  					// render pink quad
  6650  
  6651  					gl.uniform1i( uniforms.renderType, 0 );
  6652  					gl.uniform2f( uniforms.scale, scale.x, scale.y );
  6653  					gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
  6654  
  6655  					state.disable( gl.BLEND );
  6656  					state.enable( gl.DEPTH_TEST );
  6657  
  6658  					gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
  6659  
  6660  
  6661  					// copy result to occlusionMap
  6662  
  6663  					state.activeTexture( gl.TEXTURE0 );
  6664  					state.bindTexture( gl.TEXTURE_2D, occlusionTexture );
  6665  					gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 );
  6666  
  6667  
  6668  					// restore graphics
  6669  
  6670  					gl.uniform1i( uniforms.renderType, 1 );
  6671  					state.disable( gl.DEPTH_TEST );
  6672  
  6673  					state.activeTexture( gl.TEXTURE1 );
  6674  					state.bindTexture( gl.TEXTURE_2D, tempTexture );
  6675  					gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
  6676  
  6677  
  6678  					// update object positions
  6679  
  6680  					flare.positionScreen.copy( screenPosition );
  6681  
  6682  					if ( flare.customUpdateCallback ) {
  6683  
  6684  						flare.customUpdateCallback( flare );
  6685  
  6686  					} else {
  6687  
  6688  						flare.updateLensFlares();
  6689  
  6690  					}
  6691  
  6692  					// render flares
  6693  
  6694  					gl.uniform1i( uniforms.renderType, 2 );
  6695  					state.enable( gl.BLEND );
  6696  
  6697  					for ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {
  6698  
  6699  						var sprite = flare.lensFlares[ j ];
  6700  
  6701  						if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) {
  6702  
  6703  							screenPosition.x = sprite.x;
  6704  							screenPosition.y = sprite.y;
  6705  							screenPosition.z = sprite.z;
  6706  
  6707  							size = sprite.size * sprite.scale / viewport.w;
  6708  
  6709  							scale.x = size * invAspect;
  6710  							scale.y = size;
  6711  
  6712  							gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
  6713  							gl.uniform2f( uniforms.scale, scale.x, scale.y );
  6714  							gl.uniform1f( uniforms.rotation, sprite.rotation );
  6715  
  6716  							gl.uniform1f( uniforms.opacity, sprite.opacity );
  6717  							gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b );
  6718  
  6719  							state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst );
  6720  							renderer.setTexture2D( sprite.texture, 1 );
  6721  
  6722  							gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
  6723  
  6724  						}
  6725  
  6726  					}
  6727  
  6728  				}
  6729  
  6730  			}
  6731  
  6732  			// restore gl
  6733  
  6734  			state.enable( gl.CULL_FACE );
  6735  			state.enable( gl.DEPTH_TEST );
  6736  			state.setDepthWrite( true );
  6737  
  6738  			renderer.resetGLState();
  6739  
  6740  		};
  6741  
  6742  		function createProgram( shader ) {
  6743  
  6744  			var program = gl.createProgram();
  6745  
  6746  			var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
  6747  			var vertexShader = gl.createShader( gl.VERTEX_SHADER );
  6748  
  6749  			var prefix = "precision " + renderer.getPrecision() + " float;\n";
  6750  
  6751  			gl.shaderSource( fragmentShader, prefix + shader.fragmentShader );
  6752  			gl.shaderSource( vertexShader, prefix + shader.vertexShader );
  6753  
  6754  			gl.compileShader( fragmentShader );
  6755  			gl.compileShader( vertexShader );
  6756  
  6757  			gl.attachShader( program, fragmentShader );
  6758  			gl.attachShader( program, vertexShader );
  6759  
  6760  			gl.linkProgram( program );
  6761  
  6762  			return program;
  6763  
  6764  		}
  6765  
  6766  	}
  6767  
  6768  	/**
  6769  	 * @author mikael emtinger / http://gomo.se/
  6770  	 * @author alteredq / http://alteredqualia.com/
  6771  	 */
  6772  
  6773  	function SpritePlugin( renderer, sprites ) {
  6774  
  6775  		var gl = renderer.context;
  6776  		var state = renderer.state;
  6777  
  6778  		var vertexBuffer, elementBuffer;
  6779  		var program, attributes, uniforms;
  6780  
  6781  		var texture;
  6782  
  6783  		// decompose matrixWorld
  6784  
  6785  		var spritePosition = new Vector3();
  6786  		var spriteRotation = new Quaternion();
  6787  		var spriteScale = new Vector3();
  6788  
  6789  		function init() {
  6790  
  6791  			var vertices = new Float32Array( [
  6792  				- 0.5, - 0.5,  0, 0,
  6793  				  0.5, - 0.5,  1, 0,
  6794  				  0.5,   0.5,  1, 1,
  6795  				- 0.5,   0.5,  0, 1
  6796  			] );
  6797  
  6798  			var faces = new Uint16Array( [
  6799  				0, 1, 2,
  6800  				0, 2, 3
  6801  			] );
  6802  
  6803  			vertexBuffer  = gl.createBuffer();
  6804  			elementBuffer = gl.createBuffer();
  6805  
  6806  			gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
  6807  			gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );
  6808  
  6809  			gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
  6810  			gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );
  6811  
  6812  			program = createProgram();
  6813  
  6814  			attributes = {
  6815  				position:			gl.getAttribLocation ( program, 'position' ),
  6816  				uv:					gl.getAttribLocation ( program, 'uv' )
  6817  			};
  6818  
  6819  			uniforms = {
  6820  				uvOffset:			gl.getUniformLocation( program, 'uvOffset' ),
  6821  				uvScale:			gl.getUniformLocation( program, 'uvScale' ),
  6822  
  6823  				rotation:			gl.getUniformLocation( program, 'rotation' ),
  6824  				scale:				gl.getUniformLocation( program, 'scale' ),
  6825  
  6826  				color:				gl.getUniformLocation( program, 'color' ),
  6827  				map:				gl.getUniformLocation( program, 'map' ),
  6828  				opacity:			gl.getUniformLocation( program, 'opacity' ),
  6829  
  6830  				modelViewMatrix: 	gl.getUniformLocation( program, 'modelViewMatrix' ),
  6831  				projectionMatrix:	gl.getUniformLocation( program, 'projectionMatrix' ),
  6832  
  6833  				fogType:			gl.getUniformLocation( program, 'fogType' ),
  6834  				fogDensity:			gl.getUniformLocation( program, 'fogDensity' ),
  6835  				fogNear:			gl.getUniformLocation( program, 'fogNear' ),
  6836  				fogFar:				gl.getUniformLocation( program, 'fogFar' ),
  6837  				fogColor:			gl.getUniformLocation( program, 'fogColor' ),
  6838  
  6839  				alphaTest:			gl.getUniformLocation( program, 'alphaTest' )
  6840  			};
  6841  
  6842  			var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
  6843  			canvas.width = 8;
  6844  			canvas.height = 8;
  6845  
  6846  			var context = canvas.getContext( '2d' );
  6847  			context.fillStyle = 'white';
  6848  			context.fillRect( 0, 0, 8, 8 );
  6849  
  6850  			texture = new Texture( canvas );
  6851  			texture.needsUpdate = true;
  6852  
  6853  		}
  6854  
  6855  		this.render = function ( scene, camera ) {
  6856  
  6857  			if ( sprites.length === 0 ) return;
  6858  
  6859  			// setup gl
  6860  
  6861  			if ( program === undefined ) {
  6862  
  6863  				init();
  6864  
  6865  			}
  6866  
  6867  			gl.useProgram( program );
  6868  
  6869  			state.initAttributes();
  6870  			state.enableAttribute( attributes.position );
  6871  			state.enableAttribute( attributes.uv );
  6872  			state.disableUnusedAttributes();
  6873  
  6874  			state.disable( gl.CULL_FACE );
  6875  			state.enable( gl.BLEND );
  6876  
  6877  			gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
  6878  			gl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 );
  6879  			gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );
  6880  
  6881  			gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
  6882  
  6883  			gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
  6884  
  6885  			state.activeTexture( gl.TEXTURE0 );
  6886  			gl.uniform1i( uniforms.map, 0 );
  6887  
  6888  			var oldFogType = 0;
  6889  			var sceneFogType = 0;
  6890  			var fog = scene.fog;
  6891  
  6892  			if ( fog ) {
  6893  
  6894  				gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b );
  6895  
  6896  				if ( fog.isFog ) {
  6897  
  6898  					gl.uniform1f( uniforms.fogNear, fog.near );
  6899  					gl.uniform1f( uniforms.fogFar, fog.far );
  6900  
  6901  					gl.uniform1i( uniforms.fogType, 1 );
  6902  					oldFogType = 1;
  6903  					sceneFogType = 1;
  6904  
  6905  				} else if ( fog.isFogExp2 ) {
  6906  
  6907  					gl.uniform1f( uniforms.fogDensity, fog.density );
  6908  
  6909  					gl.uniform1i( uniforms.fogType, 2 );
  6910  					oldFogType = 2;
  6911  					sceneFogType = 2;
  6912  
  6913  				}
  6914  
  6915  			} else {
  6916  
  6917  				gl.uniform1i( uniforms.fogType, 0 );
  6918  				oldFogType = 0;
  6919  				sceneFogType = 0;
  6920  
  6921  			}
  6922  
  6923  
  6924  			// update positions and sort
  6925  
  6926  			for ( var i = 0, l = sprites.length; i < l; i ++ ) {
  6927  
  6928  				var sprite = sprites[ i ];
  6929  
  6930  				sprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );
  6931  				sprite.z = - sprite.modelViewMatrix.elements[ 14 ];
  6932  
  6933  			}
  6934  
  6935  			sprites.sort( painterSortStable );
  6936  
  6937  			// render all sprites
  6938  
  6939  			var scale = [];
  6940  
  6941  			for ( var i = 0, l = sprites.length; i < l; i ++ ) {
  6942  
  6943  				var sprite = sprites[ i ];
  6944  				var material = sprite.material;
  6945  
  6946  				if ( material.visible === false ) continue;
  6947  
  6948  				gl.uniform1f( uniforms.alphaTest, material.alphaTest );
  6949  				gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements );
  6950  
  6951  				sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale );
  6952  
  6953  				scale[ 0 ] = spriteScale.x;
  6954  				scale[ 1 ] = spriteScale.y;
  6955  
  6956  				var fogType = 0;
  6957  
  6958  				if ( scene.fog && material.fog ) {
  6959  
  6960  					fogType = sceneFogType;
  6961  
  6962  				}
  6963  
  6964  				if ( oldFogType !== fogType ) {
  6965  
  6966  					gl.uniform1i( uniforms.fogType, fogType );
  6967  					oldFogType = fogType;
  6968  
  6969  				}
  6970  
  6971  				if ( material.map !== null ) {
  6972  
  6973  					gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y );
  6974  					gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y );
  6975  
  6976  				} else {
  6977  
  6978  					gl.uniform2f( uniforms.uvOffset, 0, 0 );
  6979  					gl.uniform2f( uniforms.uvScale, 1, 1 );
  6980  
  6981  				}
  6982  
  6983  				gl.uniform1f( uniforms.opacity, material.opacity );
  6984  				gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );
  6985  
  6986  				gl.uniform1f( uniforms.rotation, material.rotation );
  6987  				gl.uniform2fv( uniforms.scale, scale );
  6988  
  6989  				state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
  6990  				state.setDepthTest( material.depthTest );
  6991  				state.setDepthWrite( material.depthWrite );
  6992  
  6993  				if ( material.map ) {
  6994  
  6995  					renderer.setTexture2D( material.map, 0 );
  6996  
  6997  				} else {
  6998  
  6999  					renderer.setTexture2D( texture, 0 );
  7000  
  7001  				}
  7002  
  7003  				gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
  7004  
  7005  			}
  7006  
  7007  			// restore gl
  7008  
  7009  			state.enable( gl.CULL_FACE );
  7010  
  7011  			renderer.resetGLState();
  7012  
  7013  		};
  7014  
  7015  		function createProgram() {
  7016  
  7017  			var program = gl.createProgram();
  7018  
  7019  			var vertexShader = gl.createShader( gl.VERTEX_SHADER );
  7020  			var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
  7021  
  7022  			gl.shaderSource( vertexShader, [
  7023  
  7024  				'precision ' + renderer.getPrecision() + ' float;',
  7025  
  7026  				'uniform mat4 modelViewMatrix;',
  7027  				'uniform mat4 projectionMatrix;',
  7028  				'uniform float rotation;',
  7029  				'uniform vec2 scale;',
  7030  				'uniform vec2 uvOffset;',
  7031  				'uniform vec2 uvScale;',
  7032  
  7033  				'attribute vec2 position;',
  7034  				'attribute vec2 uv;',
  7035  
  7036  				'varying vec2 vUV;',
  7037  
  7038  				'void main() {',
  7039  
  7040  					'vUV = uvOffset + uv * uvScale;',
  7041  
  7042  					'vec2 alignedPosition = position * scale;',
  7043  
  7044  					'vec2 rotatedPosition;',
  7045  					'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;',
  7046  					'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;',
  7047  
  7048  					'vec4 finalPosition;',
  7049  
  7050  					'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );',
  7051  					'finalPosition.xy += rotatedPosition;',
  7052  					'finalPosition = projectionMatrix * finalPosition;',
  7053  
  7054  					'gl_Position = finalPosition;',
  7055  
  7056  				'}'
  7057  
  7058  			].join( '\n' ) );
  7059  
  7060  			gl.shaderSource( fragmentShader, [
  7061  
  7062  				'precision ' + renderer.getPrecision() + ' float;',
  7063  
  7064  				'uniform vec3 color;',
  7065  				'uniform sampler2D map;',
  7066  				'uniform float opacity;',
  7067  
  7068  				'uniform int fogType;',
  7069  				'uniform vec3 fogColor;',
  7070  				'uniform float fogDensity;',
  7071  				'uniform float fogNear;',
  7072  				'uniform float fogFar;',
  7073  				'uniform float alphaTest;',
  7074  
  7075  				'varying vec2 vUV;',
  7076  
  7077  				'void main() {',
  7078  
  7079  					'vec4 texture = texture2D( map, vUV );',
  7080  
  7081  					'if ( texture.a < alphaTest ) discard;',
  7082  
  7083  					'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );',
  7084  
  7085  					'if ( fogType > 0 ) {',
  7086  
  7087  						'float depth = gl_FragCoord.z / gl_FragCoord.w;',
  7088  						'float fogFactor = 0.0;',
  7089  
  7090  						'if ( fogType == 1 ) {',
  7091  
  7092  							'fogFactor = smoothstep( fogNear, fogFar, depth );',
  7093  
  7094  						'} else {',
  7095  
  7096  							'const float LOG2 = 1.442695;',
  7097  							'fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );',
  7098  							'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );',
  7099  
  7100  						'}',
  7101  
  7102  						'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );',
  7103  
  7104  					'}',
  7105  
  7106  				'}'
  7107  
  7108  			].join( '\n' ) );
  7109  
  7110  			gl.compileShader( vertexShader );
  7111  			gl.compileShader( fragmentShader );
  7112  
  7113  			gl.attachShader( program, vertexShader );
  7114  			gl.attachShader( program, fragmentShader );
  7115  
  7116  			gl.linkProgram( program );
  7117  
  7118  			return program;
  7119  
  7120  		}
  7121  
  7122  		function painterSortStable( a, b ) {
  7123  
  7124  			if ( a.renderOrder !== b.renderOrder ) {
  7125  
  7126  				return a.renderOrder - b.renderOrder;
  7127  
  7128  			} else if ( a.z !== b.z ) {
  7129  
  7130  				return b.z - a.z;
  7131  
  7132  			} else {
  7133  
  7134  				return b.id - a.id;
  7135  
  7136  			}
  7137  
  7138  		}
  7139  
  7140  	}
  7141  
  7142  	/**
  7143  	 * @author mrdoob / http://mrdoob.com/
  7144  	 * @author alteredq / http://alteredqualia.com/
  7145  	 */
  7146  
  7147  	var materialId = 0;
  7148  
  7149  	function Material() {
  7150  
  7151  		Object.defineProperty( this, 'id', { value: materialId ++ } );
  7152  
  7153  		this.uuid = _Math.generateUUID();
  7154  
  7155  		this.name = '';
  7156  		this.type = 'Material';
  7157  
  7158  		this.fog = true;
  7159  		this.lights = true;
  7160  
  7161  		this.blending = NormalBlending;
  7162  		this.side = FrontSide;
  7163  		this.shading = SmoothShading; // THREE.FlatShading, THREE.SmoothShading
  7164  		this.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors
  7165  
  7166  		this.opacity = 1;
  7167  		this.transparent = false;
  7168  
  7169  		this.blendSrc = SrcAlphaFactor;
  7170  		this.blendDst = OneMinusSrcAlphaFactor;
  7171  		this.blendEquation = AddEquation;
  7172  		this.blendSrcAlpha = null;
  7173  		this.blendDstAlpha = null;
  7174  		this.blendEquationAlpha = null;
  7175  
  7176  		this.depthFunc = LessEqualDepth;
  7177  		this.depthTest = true;
  7178  		this.depthWrite = true;
  7179  
  7180  		this.clippingPlanes = null;
  7181  		this.clipIntersection = false;
  7182  		this.clipShadows = false;
  7183  
  7184  		this.colorWrite = true;
  7185  
  7186  		this.precision = null; // override the renderer's default precision for this material
  7187  
  7188  		this.polygonOffset = false;
  7189  		this.polygonOffsetFactor = 0;
  7190  		this.polygonOffsetUnits = 0;
  7191  
  7192  		this.alphaTest = 0;
  7193  		this.premultipliedAlpha = false;
  7194  
  7195  		this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer
  7196  
  7197  		this.visible = true;
  7198  
  7199  		this._needsUpdate = true;
  7200  
  7201  	}
  7202  
  7203  	Material.prototype = {
  7204  
  7205  		constructor: Material,
  7206  
  7207  		isMaterial: true,
  7208  
  7209  		get needsUpdate() {
  7210  
  7211  			return this._needsUpdate;
  7212  
  7213  		},
  7214  
  7215  		set needsUpdate( value ) {
  7216  
  7217  			if ( value === true ) this.update();
  7218  			this._needsUpdate = value;
  7219  
  7220  		},
  7221  
  7222  		setValues: function ( values ) {
  7223  
  7224  			if ( values === undefined ) return;
  7225  
  7226  			for ( var key in values ) {
  7227  
  7228  				var newValue = values[ key ];
  7229  
  7230  				if ( newValue === undefined ) {
  7231  
  7232  					console.warn( "THREE.Material: '" + key + "' parameter is undefined." );
  7233  					continue;
  7234  
  7235  				}
  7236  
  7237  				var currentValue = this[ key ];
  7238  
  7239  				if ( currentValue === undefined ) {
  7240  
  7241  					console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." );
  7242  					continue;
  7243  
  7244  				}
  7245  
  7246  				if ( currentValue && currentValue.isColor ) {
  7247  
  7248  					currentValue.set( newValue );
  7249  
  7250  				} else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
  7251  
  7252  					currentValue.copy( newValue );
  7253  
  7254  				} else if ( key === 'overdraw' ) {
  7255  
  7256  					// ensure overdraw is backwards-compatible with legacy boolean type
  7257  					this[ key ] = Number( newValue );
  7258  
  7259  				} else {
  7260  
  7261  					this[ key ] = newValue;
  7262  
  7263  				}
  7264  
  7265  			}
  7266  
  7267  		},
  7268  
  7269  		toJSON: function ( meta ) {
  7270  
  7271  			var isRoot = meta === undefined;
  7272  
  7273  			if ( isRoot ) {
  7274  
  7275  				meta = {
  7276  					textures: {},
  7277  					images: {}
  7278  				};
  7279  
  7280  			}
  7281  
  7282  			var data = {
  7283  				metadata: {
  7284  					version: 4.4,
  7285  					type: 'Material',
  7286  					generator: 'Material.toJSON'
  7287  				}
  7288  			};
  7289  
  7290  			// standard Material serialization
  7291  			data.uuid = this.uuid;
  7292  			data.type = this.type;
  7293  
  7294  			if ( this.name !== '' ) data.name = this.name;
  7295  
  7296  			if ( this.color && this.color.isColor ) data.color = this.color.getHex();
  7297  
  7298  			if ( this.roughness !== undefined ) data.roughness = this.roughness;
  7299  			if ( this.metalness !== undefined ) data.metalness = this.metalness;
  7300  
  7301  			if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
  7302  			if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
  7303  			if ( this.shininess !== undefined ) data.shininess = this.shininess;
  7304  			if ( this.clearCoat !== undefined ) data.clearCoat = this.clearCoat;
  7305  			if ( this.clearCoatRoughness !== undefined ) data.clearCoatRoughness = this.clearCoatRoughness;
  7306  
  7307  			if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
  7308  			if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
  7309  			if ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid;
  7310  			if ( this.bumpMap && this.bumpMap.isTexture ) {
  7311  
  7312  				data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
  7313  				data.bumpScale = this.bumpScale;
  7314  
  7315  			}
  7316  			if ( this.normalMap && this.normalMap.isTexture ) {
  7317  
  7318  				data.normalMap = this.normalMap.toJSON( meta ).uuid;
  7319  				data.normalScale = this.normalScale.toArray();
  7320  
  7321  			}
  7322  			if ( this.displacementMap && this.displacementMap.isTexture ) {
  7323  
  7324  				data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
  7325  				data.displacementScale = this.displacementScale;
  7326  				data.displacementBias = this.displacementBias;
  7327  
  7328  			}
  7329  			if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
  7330  			if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
  7331  
  7332  			if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
  7333  			if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
  7334  
  7335  			if ( this.envMap && this.envMap.isTexture ) {
  7336  
  7337  				data.envMap = this.envMap.toJSON( meta ).uuid;
  7338  				data.reflectivity = this.reflectivity; // Scale behind envMap
  7339  
  7340  			}
  7341  
  7342  			if ( this.gradientMap && this.gradientMap.isTexture ) {
  7343  
  7344  				data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
  7345  
  7346  			}
  7347  
  7348  			if ( this.size !== undefined ) data.size = this.size;
  7349  			if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
  7350  
  7351  			if ( this.blending !== NormalBlending ) data.blending = this.blending;
  7352  			if ( this.shading !== SmoothShading ) data.shading = this.shading;
  7353  			if ( this.side !== FrontSide ) data.side = this.side;
  7354  			if ( this.vertexColors !== NoColors ) data.vertexColors = this.vertexColors;
  7355  
  7356  			if ( this.opacity < 1 ) data.opacity = this.opacity;
  7357  			if ( this.transparent === true ) data.transparent = this.transparent;
  7358  
  7359  			data.depthFunc = this.depthFunc;
  7360  			data.depthTest = this.depthTest;
  7361  			data.depthWrite = this.depthWrite;
  7362  
  7363  			if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
  7364  			if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
  7365  			if ( this.wireframe === true ) data.wireframe = this.wireframe;
  7366  			if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
  7367  			if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
  7368  			if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
  7369  
  7370  			data.skinning = this.skinning;
  7371  			data.morphTargets = this.morphTargets;
  7372  
  7373  			// TODO: Copied from Object3D.toJSON
  7374  
  7375  			function extractFromCache( cache ) {
  7376  
  7377  				var values = [];
  7378  
  7379  				for ( var key in cache ) {
  7380  
  7381  					var data = cache[ key ];
  7382  					delete data.metadata;
  7383  					values.push( data );
  7384  
  7385  				}
  7386  
  7387  				return values;
  7388  
  7389  			}
  7390  
  7391  			if ( isRoot ) {
  7392  
  7393  				var textures = extractFromCache( meta.textures );
  7394  				var images = extractFromCache( meta.images );
  7395  
  7396  				if ( textures.length > 0 ) data.textures = textures;
  7397  				if ( images.length > 0 ) data.images = images;
  7398  
  7399  			}
  7400  
  7401  			return data;
  7402  
  7403  		},
  7404  
  7405  		clone: function () {
  7406  
  7407  			return new this.constructor().copy( this );
  7408  
  7409  		},
  7410  
  7411  		copy: function ( source ) {
  7412  
  7413  			this.name = source.name;
  7414  
  7415  			this.fog = source.fog;
  7416  			this.lights = source.lights;
  7417  
  7418  			this.blending = source.blending;
  7419  			this.side = source.side;
  7420  			this.shading = source.shading;
  7421  			this.vertexColors = source.vertexColors;
  7422  
  7423  			this.opacity = source.opacity;
  7424  			this.transparent = source.transparent;
  7425  
  7426  			this.blendSrc = source.blendSrc;
  7427  			this.blendDst = source.blendDst;
  7428  			this.blendEquation = source.blendEquation;
  7429  			this.blendSrcAlpha = source.blendSrcAlpha;
  7430  			this.blendDstAlpha = source.blendDstAlpha;
  7431  			this.blendEquationAlpha = source.blendEquationAlpha;
  7432  
  7433  			this.depthFunc = source.depthFunc;
  7434  			this.depthTest = source.depthTest;
  7435  			this.depthWrite = source.depthWrite;
  7436  
  7437  			this.colorWrite = source.colorWrite;
  7438  
  7439  			this.precision = source.precision;
  7440  
  7441  			this.polygonOffset = source.polygonOffset;
  7442  			this.polygonOffsetFactor = source.polygonOffsetFactor;
  7443  			this.polygonOffsetUnits = source.polygonOffsetUnits;
  7444  
  7445  			this.alphaTest = source.alphaTest;
  7446  
  7447  			this.premultipliedAlpha = source.premultipliedAlpha;
  7448  
  7449  			this.overdraw = source.overdraw;
  7450  
  7451  			this.visible = source.visible;
  7452  			this.clipShadows = source.clipShadows;
  7453  			this.clipIntersection = source.clipIntersection;
  7454  
  7455  			var srcPlanes = source.clippingPlanes,
  7456  				dstPlanes = null;
  7457  
  7458  			if ( srcPlanes !== null ) {
  7459  
  7460  				var n = srcPlanes.length;
  7461  				dstPlanes = new Array( n );
  7462  
  7463  				for ( var i = 0; i !== n; ++ i )
  7464  					dstPlanes[ i ] = srcPlanes[ i ].clone();
  7465  
  7466  			}
  7467  
  7468  			this.clippingPlanes = dstPlanes;
  7469  
  7470  			return this;
  7471  
  7472  		},
  7473  
  7474  		update: function () {
  7475  
  7476  			this.dispatchEvent( { type: 'update' } );
  7477  
  7478  		},
  7479  
  7480  		dispose: function () {
  7481  
  7482  			this.dispatchEvent( { type: 'dispose' } );
  7483  
  7484  		}
  7485  
  7486  	};
  7487  
  7488  	Object.assign( Material.prototype, EventDispatcher.prototype );
  7489  
  7490  	/**
  7491  	 * @author alteredq / http://alteredqualia.com/
  7492  	 *
  7493  	 * parameters = {
  7494  	 *  defines: { "label" : "value" },
  7495  	 *  uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } },
  7496  	 *
  7497  	 *  fragmentShader: <string>,
  7498  	 *  vertexShader: <string>,
  7499  	 *
  7500  	 *  wireframe: <boolean>,
  7501  	 *  wireframeLinewidth: <float>,
  7502  	 *
  7503  	 *  lights: <bool>,
  7504  	 *
  7505  	 *  skinning: <bool>,
  7506  	 *  morphTargets: <bool>,
  7507  	 *  morphNormals: <bool>
  7508  	 * }
  7509  	 */
  7510  
  7511  	function ShaderMaterial( parameters ) {
  7512  
  7513  		Material.call( this );
  7514  
  7515  		this.type = 'ShaderMaterial';
  7516  
  7517  		this.defines = {};
  7518  		this.uniforms = {};
  7519  
  7520  		this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}';
  7521  		this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}';
  7522  
  7523  		this.linewidth = 1;
  7524  
  7525  		this.wireframe = false;
  7526  		this.wireframeLinewidth = 1;
  7527  
  7528  		this.fog = false; // set to use scene fog
  7529  		this.lights = false; // set to use scene lights
  7530  		this.clipping = false; // set to use user-defined clipping planes
  7531  
  7532  		this.skinning = false; // set to use skinning attribute streams
  7533  		this.morphTargets = false; // set to use morph targets
  7534  		this.morphNormals = false; // set to use morph normals
  7535  
  7536  		this.extensions = {
  7537  			derivatives: false, // set to use derivatives
  7538  			fragDepth: false, // set to use fragment depth values
  7539  			drawBuffers: false, // set to use draw buffers
  7540  			shaderTextureLOD: false // set to use shader texture LOD
  7541  		};
  7542  
  7543  		// When rendered geometry doesn't include these attributes but the material does,
  7544  		// use these default values in WebGL. This avoids errors when buffer data is missing.
  7545  		this.defaultAttributeValues = {
  7546  			'color': [ 1, 1, 1 ],
  7547  			'uv': [ 0, 0 ],
  7548  			'uv2': [ 0, 0 ]
  7549  		};
  7550  
  7551  		this.index0AttributeName = undefined;
  7552  
  7553  		if ( parameters !== undefined ) {
  7554  
  7555  			if ( parameters.attributes !== undefined ) {
  7556  
  7557  				console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' );
  7558  
  7559  			}
  7560  
  7561  			this.setValues( parameters );
  7562  
  7563  		}
  7564  
  7565  	}
  7566  
  7567  	ShaderMaterial.prototype = Object.create( Material.prototype );
  7568  	ShaderMaterial.prototype.constructor = ShaderMaterial;
  7569  
  7570  	ShaderMaterial.prototype.isShaderMaterial = true;
  7571  
  7572  	ShaderMaterial.prototype.copy = function ( source ) {
  7573  
  7574  		Material.prototype.copy.call( this, source );
  7575  
  7576  		this.fragmentShader = source.fragmentShader;
  7577  		this.vertexShader = source.vertexShader;
  7578  
  7579  		this.uniforms = UniformsUtils.clone( source.uniforms );
  7580  
  7581  		this.defines = source.defines;
  7582  
  7583  		this.wireframe = source.wireframe;
  7584  		this.wireframeLinewidth = source.wireframeLinewidth;
  7585  
  7586  		this.lights = source.lights;
  7587  		this.clipping = source.clipping;
  7588  
  7589  		this.skinning = source.skinning;
  7590  
  7591  		this.morphTargets = source.morphTargets;
  7592  		this.morphNormals = source.morphNormals;
  7593  
  7594  		this.extensions = source.extensions;
  7595  
  7596  		return this;
  7597  
  7598  	};
  7599  
  7600  	ShaderMaterial.prototype.toJSON = function ( meta ) {
  7601  
  7602  		var data = Material.prototype.toJSON.call( this, meta );
  7603  
  7604  		data.uniforms = this.uniforms;
  7605  		data.vertexShader = this.vertexShader;
  7606  		data.fragmentShader = this.fragmentShader;
  7607  
  7608  		return data;
  7609  
  7610  	};
  7611  
  7612  	/**
  7613  	 * @author mrdoob / http://mrdoob.com/
  7614  	 * @author alteredq / http://alteredqualia.com/
  7615  	 * @author bhouston / https://clara.io
  7616  	 * @author WestLangley / http://github.com/WestLangley
  7617  	 *
  7618  	 * parameters = {
  7619  	 *
  7620  	 *  opacity: <float>,
  7621  	 *
  7622  	 *  map: new THREE.Texture( <Image> ),
  7623  	 *
  7624  	 *  alphaMap: new THREE.Texture( <Image> ),
  7625  	 *
  7626  	 *  displacementMap: new THREE.Texture( <Image> ),
  7627  	 *  displacementScale: <float>,
  7628  	 *  displacementBias: <float>,
  7629  	 *
  7630  	 *  wireframe: <boolean>,
  7631  	 *  wireframeLinewidth: <float>
  7632  	 * }
  7633  	 */
  7634  
  7635  	function MeshDepthMaterial( parameters ) {
  7636  
  7637  		Material.call( this );
  7638  
  7639  		this.type = 'MeshDepthMaterial';
  7640  
  7641  		this.depthPacking = BasicDepthPacking;
  7642  
  7643  		this.skinning = false;
  7644  		this.morphTargets = false;
  7645  
  7646  		this.map = null;
  7647  
  7648  		this.alphaMap = null;
  7649  
  7650  		this.displacementMap = null;
  7651  		this.displacementScale = 1;
  7652  		this.displacementBias = 0;
  7653  
  7654  		this.wireframe = false;
  7655  		this.wireframeLinewidth = 1;
  7656  
  7657  		this.fog = false;
  7658  		this.lights = false;
  7659  
  7660  		this.setValues( parameters );
  7661  
  7662  	}
  7663  
  7664  	MeshDepthMaterial.prototype = Object.create( Material.prototype );
  7665  	MeshDepthMaterial.prototype.constructor = MeshDepthMaterial;
  7666  
  7667  	MeshDepthMaterial.prototype.isMeshDepthMaterial = true;
  7668  
  7669  	MeshDepthMaterial.prototype.copy = function ( source ) {
  7670  
  7671  		Material.prototype.copy.call( this, source );
  7672  
  7673  		this.depthPacking = source.depthPacking;
  7674  
  7675  		this.skinning = source.skinning;
  7676  		this.morphTargets = source.morphTargets;
  7677  
  7678  		this.map = source.map;
  7679  
  7680  		this.alphaMap = source.alphaMap;
  7681  
  7682  		this.displacementMap = source.displacementMap;
  7683  		this.displacementScale = source.displacementScale;
  7684  		this.displacementBias = source.displacementBias;
  7685  
  7686  		this.wireframe = source.wireframe;
  7687  		this.wireframeLinewidth = source.wireframeLinewidth;
  7688  
  7689  		return this;
  7690  
  7691  	};
  7692  
  7693  	/**
  7694  	 * @author bhouston / http://clara.io
  7695  	 * @author WestLangley / http://github.com/WestLangley
  7696  	 */
  7697  
  7698  	function Box3( min, max ) {
  7699  
  7700  		this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );
  7701  		this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity );
  7702  
  7703  	}
  7704  
  7705  	Box3.prototype = {
  7706  
  7707  		constructor: Box3,
  7708  
  7709  		isBox3: true,
  7710  
  7711  		set: function ( min, max ) {
  7712  
  7713  			this.min.copy( min );
  7714  			this.max.copy( max );
  7715  
  7716  			return this;
  7717  
  7718  		},
  7719  
  7720  		setFromArray: function ( array ) {
  7721  
  7722  			var minX = + Infinity;
  7723  			var minY = + Infinity;
  7724  			var minZ = + Infinity;
  7725  
  7726  			var maxX = - Infinity;
  7727  			var maxY = - Infinity;
  7728  			var maxZ = - Infinity;
  7729  
  7730  			for ( var i = 0, l = array.length; i < l; i += 3 ) {
  7731  
  7732  				var x = array[ i ];
  7733  				var y = array[ i + 1 ];
  7734  				var z = array[ i + 2 ];
  7735  
  7736  				if ( x < minX ) minX = x;
  7737  				if ( y < minY ) minY = y;
  7738  				if ( z < minZ ) minZ = z;
  7739  
  7740  				if ( x > maxX ) maxX = x;
  7741  				if ( y > maxY ) maxY = y;
  7742  				if ( z > maxZ ) maxZ = z;
  7743  
  7744  			}
  7745  
  7746  			this.min.set( minX, minY, minZ );
  7747  			this.max.set( maxX, maxY, maxZ );
  7748  
  7749  			return this;
  7750  
  7751  		},
  7752  
  7753  		setFromBufferAttribute: function ( attribute ) {
  7754  
  7755  			var minX = + Infinity;
  7756  			var minY = + Infinity;
  7757  			var minZ = + Infinity;
  7758  
  7759  			var maxX = - Infinity;
  7760  			var maxY = - Infinity;
  7761  			var maxZ = - Infinity;
  7762  
  7763  			for ( var i = 0, l = attribute.count; i < l; i ++ ) {
  7764  
  7765  				var x = attribute.getX( i );
  7766  				var y = attribute.getY( i );
  7767  				var z = attribute.getZ( i );
  7768  
  7769  				if ( x < minX ) minX = x;
  7770  				if ( y < minY ) minY = y;
  7771  				if ( z < minZ ) minZ = z;
  7772  
  7773  				if ( x > maxX ) maxX = x;
  7774  				if ( y > maxY ) maxY = y;
  7775  				if ( z > maxZ ) maxZ = z;
  7776  
  7777  			}
  7778  
  7779  			this.min.set( minX, minY, minZ );
  7780  			this.max.set( maxX, maxY, maxZ );
  7781  
  7782  			return this;
  7783  
  7784  		},
  7785  
  7786  		setFromPoints: function ( points ) {
  7787  
  7788  			this.makeEmpty();
  7789  
  7790  			for ( var i = 0, il = points.length; i < il; i ++ ) {
  7791  
  7792  				this.expandByPoint( points[ i ] );
  7793  
  7794  			}
  7795  
  7796  			return this;
  7797  
  7798  		},
  7799  
  7800  		setFromCenterAndSize: function () {
  7801  
  7802  			var v1 = new Vector3();
  7803  
  7804  			return function setFromCenterAndSize( center, size ) {
  7805  
  7806  				var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
  7807  
  7808  				this.min.copy( center ).sub( halfSize );
  7809  				this.max.copy( center ).add( halfSize );
  7810  
  7811  				return this;
  7812  
  7813  			};
  7814  
  7815  		}(),
  7816  
  7817  		setFromObject: function ( object ) {
  7818  
  7819  			this.makeEmpty();
  7820  
  7821  			return this.expandByObject( object );
  7822  
  7823  		},
  7824  
  7825  		clone: function () {
  7826  
  7827  			return new this.constructor().copy( this );
  7828  
  7829  		},
  7830  
  7831  		copy: function ( box ) {
  7832  
  7833  			this.min.copy( box.min );
  7834  			this.max.copy( box.max );
  7835  
  7836  			return this;
  7837  
  7838  		},
  7839  
  7840  		makeEmpty: function () {
  7841  
  7842  			this.min.x = this.min.y = this.min.z = + Infinity;
  7843  			this.max.x = this.max.y = this.max.z = - Infinity;
  7844  
  7845  			return this;
  7846  
  7847  		},
  7848  
  7849  		isEmpty: function () {
  7850  
  7851  			// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
  7852  
  7853  			return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
  7854  
  7855  		},
  7856  
  7857  		getCenter: function ( optionalTarget ) {
  7858  
  7859  			var result = optionalTarget || new Vector3();
  7860  			return this.isEmpty() ? result.set( 0, 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
  7861  
  7862  		},
  7863  
  7864  		getSize: function ( optionalTarget ) {
  7865  
  7866  			var result = optionalTarget || new Vector3();
  7867  			return this.isEmpty() ? result.set( 0, 0, 0 ) : result.subVectors( this.max, this.min );
  7868  
  7869  		},
  7870  
  7871  		expandByPoint: function ( point ) {
  7872  
  7873  			this.min.min( point );
  7874  			this.max.max( point );
  7875  
  7876  			return this;
  7877  
  7878  		},
  7879  
  7880  		expandByVector: function ( vector ) {
  7881  
  7882  			this.min.sub( vector );
  7883  			this.max.add( vector );
  7884  
  7885  			return this;
  7886  
  7887  		},
  7888  
  7889  		expandByScalar: function ( scalar ) {
  7890  
  7891  			this.min.addScalar( - scalar );
  7892  			this.max.addScalar( scalar );
  7893  
  7894  			return this;
  7895  
  7896  		},
  7897  
  7898  		expandByObject: function () {
  7899  
  7900  			// Computes the world-axis-aligned bounding box of an object (including its children),
  7901  			// accounting for both the object's, and children's, world transforms
  7902  
  7903  			var v1 = new Vector3();
  7904  
  7905  			return function expandByObject( object ) {
  7906  
  7907  				var scope = this;
  7908  
  7909  				object.updateMatrixWorld( true );
  7910  
  7911  				object.traverse( function ( node ) {
  7912  
  7913  					var i, l;
  7914  
  7915  					var geometry = node.geometry;
  7916  
  7917  					if ( geometry !== undefined ) {
  7918  
  7919  						if ( geometry.isGeometry ) {
  7920  
  7921  							var vertices = geometry.vertices;
  7922  
  7923  							for ( i = 0, l = vertices.length; i < l; i ++ ) {
  7924  
  7925  								v1.copy( vertices[ i ] );
  7926  								v1.applyMatrix4( node.matrixWorld );
  7927  
  7928  								scope.expandByPoint( v1 );
  7929  
  7930  							}
  7931  
  7932  						} else if ( geometry.isBufferGeometry ) {
  7933  
  7934  							var attribute = geometry.attributes.position;
  7935  
  7936  							if ( attribute !== undefined ) {
  7937  
  7938  								for ( i = 0, l = attribute.count; i < l; i ++ ) {
  7939  
  7940  									v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld );
  7941  
  7942  									scope.expandByPoint( v1 );
  7943  
  7944  								}
  7945  
  7946  							}
  7947  
  7948  						}
  7949  
  7950  					}
  7951  
  7952  				} );
  7953  
  7954  				return this;
  7955  
  7956  			};
  7957  
  7958  		}(),
  7959  
  7960  		containsPoint: function ( point ) {
  7961  
  7962  			return point.x < this.min.x || point.x > this.max.x ||
  7963  				point.y < this.min.y || point.y > this.max.y ||
  7964  				point.z < this.min.z || point.z > this.max.z ? false : true;
  7965  
  7966  		},
  7967  
  7968  		containsBox: function ( box ) {
  7969  
  7970  			return this.min.x <= box.min.x && box.max.x <= this.max.x &&
  7971  				this.min.y <= box.min.y && box.max.y <= this.max.y &&
  7972  				this.min.z <= box.min.z && box.max.z <= this.max.z;
  7973  
  7974  		},
  7975  
  7976  		getParameter: function ( point, optionalTarget ) {
  7977  
  7978  			// This can potentially have a divide by zero if the box
  7979  			// has a size dimension of 0.
  7980  
  7981  			var result = optionalTarget || new Vector3();
  7982  
  7983  			return result.set(
  7984  				( point.x - this.min.x ) / ( this.max.x - this.min.x ),
  7985  				( point.y - this.min.y ) / ( this.max.y - this.min.y ),
  7986  				( point.z - this.min.z ) / ( this.max.z - this.min.z )
  7987  			);
  7988  
  7989  		},
  7990  
  7991  		intersectsBox: function ( box ) {
  7992  
  7993  			// using 6 splitting planes to rule out intersections.
  7994  			return box.max.x < this.min.x || box.min.x > this.max.x ||
  7995  				box.max.y < this.min.y || box.min.y > this.max.y ||
  7996  				box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
  7997  
  7998  		},
  7999  
  8000  		intersectsSphere: ( function () {
  8001  
  8002  			var closestPoint;
  8003  
  8004  			return function intersectsSphere( sphere ) {
  8005  
  8006  				if ( closestPoint === undefined ) closestPoint = new Vector3();
  8007  
  8008  				// Find the point on the AABB closest to the sphere center.
  8009  				this.clampPoint( sphere.center, closestPoint );
  8010  
  8011  				// If that point is inside the sphere, the AABB and sphere intersect.
  8012  				return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
  8013  
  8014  			};
  8015  
  8016  		} )(),
  8017  
  8018  		intersectsPlane: function ( plane ) {
  8019  
  8020  			// We compute the minimum and maximum dot product values. If those values
  8021  			// are on the same side (back or front) of the plane, then there is no intersection.
  8022  
  8023  			var min, max;
  8024  
  8025  			if ( plane.normal.x > 0 ) {
  8026  
  8027  				min = plane.normal.x * this.min.x;
  8028  				max = plane.normal.x * this.max.x;
  8029  
  8030  			} else {
  8031  
  8032  				min = plane.normal.x * this.max.x;
  8033  				max = plane.normal.x * this.min.x;
  8034  
  8035  			}
  8036  
  8037  			if ( plane.normal.y > 0 ) {
  8038  
  8039  				min += plane.normal.y * this.min.y;
  8040  				max += plane.normal.y * this.max.y;
  8041  
  8042  			} else {
  8043  
  8044  				min += plane.normal.y * this.max.y;
  8045  				max += plane.normal.y * this.min.y;
  8046  
  8047  			}
  8048  
  8049  			if ( plane.normal.z > 0 ) {
  8050  
  8051  				min += plane.normal.z * this.min.z;
  8052  				max += plane.normal.z * this.max.z;
  8053  
  8054  			} else {
  8055  
  8056  				min += plane.normal.z * this.max.z;
  8057  				max += plane.normal.z * this.min.z;
  8058  
  8059  			}
  8060  
  8061  			return ( min <= plane.constant && max >= plane.constant );
  8062  
  8063  		},
  8064  
  8065  		clampPoint: function ( point, optionalTarget ) {
  8066  
  8067  			var result = optionalTarget || new Vector3();
  8068  			return result.copy( point ).clamp( this.min, this.max );
  8069  
  8070  		},
  8071  
  8072  		distanceToPoint: function () {
  8073  
  8074  			var v1 = new Vector3();
  8075  
  8076  			return function distanceToPoint( point ) {
  8077  
  8078  				var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
  8079  				return clampedPoint.sub( point ).length();
  8080  
  8081  			};
  8082  
  8083  		}(),
  8084  
  8085  		getBoundingSphere: function () {
  8086  
  8087  			var v1 = new Vector3();
  8088  
  8089  			return function getBoundingSphere( optionalTarget ) {
  8090  
  8091  				var result = optionalTarget || new Sphere();
  8092  
  8093  				this.getCenter( result.center );
  8094  
  8095  				result.radius = this.getSize( v1 ).length() * 0.5;
  8096  
  8097  				return result;
  8098  
  8099  			};
  8100  
  8101  		}(),
  8102  
  8103  		intersect: function ( box ) {
  8104  
  8105  			this.min.max( box.min );
  8106  			this.max.min( box.max );
  8107  
  8108  			// ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
  8109  			if( this.isEmpty() ) this.makeEmpty();
  8110  
  8111  			return this;
  8112  
  8113  		},
  8114  
  8115  		union: function ( box ) {
  8116  
  8117  			this.min.min( box.min );
  8118  			this.max.max( box.max );
  8119  
  8120  			return this;
  8121  
  8122  		},
  8123  
  8124  		applyMatrix4: function () {
  8125  
  8126  			var points = [
  8127  				new Vector3(),
  8128  				new Vector3(),
  8129  				new Vector3(),
  8130  				new Vector3(),
  8131  				new Vector3(),
  8132  				new Vector3(),
  8133  				new Vector3(),
  8134  				new Vector3()
  8135  			];
  8136  
  8137  			return function applyMatrix4( matrix ) {
  8138  
  8139  				// transform of empty box is an empty box.
  8140  				if( this.isEmpty() ) return this;
  8141  
  8142  				// NOTE: I am using a binary pattern to specify all 2^3 combinations below
  8143  				points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
  8144  				points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
  8145  				points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
  8146  				points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
  8147  				points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
  8148  				points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
  8149  				points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
  8150  				points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix );	// 111
  8151  
  8152  				this.setFromPoints( points );
  8153  
  8154  				return this;
  8155  
  8156  			};
  8157  
  8158  		}(),
  8159  
  8160  		translate: function ( offset ) {
  8161  
  8162  			this.min.add( offset );
  8163  			this.max.add( offset );
  8164  
  8165  			return this;
  8166  
  8167  		},
  8168  
  8169  		equals: function ( box ) {
  8170  
  8171  			return box.min.equals( this.min ) && box.max.equals( this.max );
  8172  
  8173  		}
  8174  
  8175  	};
  8176  
  8177  	/**
  8178  	 * @author bhouston / http://clara.io
  8179  	 * @author mrdoob / http://mrdoob.com/
  8180  	 */
  8181  
  8182  	function Sphere( center, radius ) {
  8183  
  8184  		this.center = ( center !== undefined ) ? center : new Vector3();
  8185  		this.radius = ( radius !== undefined ) ? radius : 0;
  8186  
  8187  	}
  8188  
  8189  	Sphere.prototype = {
  8190  
  8191  		constructor: Sphere,
  8192  
  8193  		set: function ( center, radius ) {
  8194  
  8195  			this.center.copy( center );
  8196  			this.radius = radius;
  8197  
  8198  			return this;
  8199  
  8200  		},
  8201  
  8202  		setFromPoints: function () {
  8203  
  8204  			var box;
  8205  
  8206  			return function setFromPoints( points, optionalCenter ) {
  8207  
  8208  				if ( box === undefined ) box = new Box3(); // see #10547
  8209  
  8210  				var center = this.center;
  8211  
  8212  				if ( optionalCenter !== undefined ) {
  8213  
  8214  					center.copy( optionalCenter );
  8215  
  8216  				} else {
  8217  
  8218  					box.setFromPoints( points ).getCenter( center );
  8219  
  8220  				}
  8221  
  8222  				var maxRadiusSq = 0;
  8223  
  8224  				for ( var i = 0, il = points.length; i < il; i ++ ) {
  8225  
  8226  					maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );
  8227  
  8228  				}
  8229  
  8230  				this.radius = Math.sqrt( maxRadiusSq );
  8231  
  8232  				return this;
  8233  
  8234  			};
  8235  
  8236  		}(),
  8237  
  8238  		clone: function () {
  8239  
  8240  			return new this.constructor().copy( this );
  8241  
  8242  		},
  8243  
  8244  		copy: function ( sphere ) {
  8245  
  8246  			this.center.copy( sphere.center );
  8247  			this.radius = sphere.radius;
  8248  
  8249  			return this;
  8250  
  8251  		},
  8252  
  8253  		empty: function () {
  8254  
  8255  			return ( this.radius <= 0 );
  8256  
  8257  		},
  8258  
  8259  		containsPoint: function ( point ) {
  8260  
  8261  			return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
  8262  
  8263  		},
  8264  
  8265  		distanceToPoint: function ( point ) {
  8266  
  8267  			return ( point.distanceTo( this.center ) - this.radius );
  8268  
  8269  		},
  8270  
  8271  		intersectsSphere: function ( sphere ) {
  8272  
  8273  			var radiusSum = this.radius + sphere.radius;
  8274  
  8275  			return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
  8276  
  8277  		},
  8278  
  8279  		intersectsBox: function ( box ) {
  8280  
  8281  			return box.intersectsSphere( this );
  8282  
  8283  		},
  8284  
  8285  		intersectsPlane: function ( plane ) {
  8286  
  8287  			// We use the following equation to compute the signed distance from
  8288  			// the center of the sphere to the plane.
  8289  			//
  8290  			// distance = q * n - d
  8291  			//
  8292  			// If this distance is greater than the radius of the sphere,
  8293  			// then there is no intersection.
  8294  
  8295  			return Math.abs( this.center.dot( plane.normal ) - plane.constant ) <= this.radius;
  8296  
  8297  		},
  8298  
  8299  		clampPoint: function ( point, optionalTarget ) {
  8300  
  8301  			var deltaLengthSq = this.center.distanceToSquared( point );
  8302  
  8303  			var result = optionalTarget || new Vector3();
  8304  
  8305  			result.copy( point );
  8306  
  8307  			if ( deltaLengthSq > ( this.radius * this.radius ) ) {
  8308  
  8309  				result.sub( this.center ).normalize();
  8310  				result.multiplyScalar( this.radius ).add( this.center );
  8311  
  8312  			}
  8313  
  8314  			return result;
  8315  
  8316  		},
  8317  
  8318  		getBoundingBox: function ( optionalTarget ) {
  8319  
  8320  			var box = optionalTarget || new Box3();
  8321  
  8322  			box.set( this.center, this.center );
  8323  			box.expandByScalar( this.radius );
  8324  
  8325  			return box;
  8326  
  8327  		},
  8328  
  8329  		applyMatrix4: function ( matrix ) {
  8330  
  8331  			this.center.applyMatrix4( matrix );
  8332  			this.radius = this.radius * matrix.getMaxScaleOnAxis();
  8333  
  8334  			return this;
  8335  
  8336  		},
  8337  
  8338  		translate: function ( offset ) {
  8339  
  8340  			this.center.add( offset );
  8341  
  8342  			return this;
  8343  
  8344  		},
  8345  
  8346  		equals: function ( sphere ) {
  8347  
  8348  			return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
  8349  
  8350  		}
  8351  
  8352  	};
  8353  
  8354  	/**
  8355  	 * @author alteredq / http://alteredqualia.com/
  8356  	 * @author WestLangley / http://github.com/WestLangley
  8357  	 * @author bhouston / http://clara.io
  8358  	 * @author tschw
  8359  	 */
  8360  
  8361  	function Matrix3() {
  8362  
  8363  		this.elements = new Float32Array( [
  8364  
  8365  			1, 0, 0,
  8366  			0, 1, 0,
  8367  			0, 0, 1
  8368  
  8369  		] );
  8370  
  8371  		if ( arguments.length > 0 ) {
  8372  
  8373  			console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );
  8374  
  8375  		}
  8376  
  8377  	}
  8378  
  8379  	Matrix3.prototype = {
  8380  
  8381  		constructor: Matrix3,
  8382  
  8383  		isMatrix3: true,
  8384  
  8385  		set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
  8386  
  8387  			var te = this.elements;
  8388  
  8389  			te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
  8390  			te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
  8391  			te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
  8392  
  8393  			return this;
  8394  
  8395  		},
  8396  
  8397  		identity: function () {
  8398  
  8399  			this.set(
  8400  
  8401  				1, 0, 0,
  8402  				0, 1, 0,
  8403  				0, 0, 1
  8404  
  8405  			);
  8406  
  8407  			return this;
  8408  
  8409  		},
  8410  
  8411  		clone: function () {
  8412  
  8413  			return new this.constructor().fromArray( this.elements );
  8414  
  8415  		},
  8416  
  8417  		copy: function ( m ) {
  8418  
  8419  			var me = m.elements;
  8420  
  8421  			this.set(
  8422  
  8423  				me[ 0 ], me[ 3 ], me[ 6 ],
  8424  				me[ 1 ], me[ 4 ], me[ 7 ],
  8425  				me[ 2 ], me[ 5 ], me[ 8 ]
  8426  
  8427  			);
  8428  
  8429  			return this;
  8430  
  8431  		},
  8432  
  8433  		setFromMatrix4: function( m ) {
  8434  
  8435  			var me = m.elements;
  8436  
  8437  			this.set(
  8438  
  8439  				me[ 0 ], me[ 4 ], me[  8 ],
  8440  				me[ 1 ], me[ 5 ], me[  9 ],
  8441  				me[ 2 ], me[ 6 ], me[ 10 ]
  8442  
  8443  			);
  8444  
  8445  			return this;
  8446  
  8447  		},
  8448  
  8449  		applyToBufferAttribute: function () {
  8450  
  8451  			var v1;
  8452  
  8453  			return function applyToBufferAttribute( attribute ) {
  8454  
  8455  				if ( v1 === undefined ) v1 = new Vector3();
  8456  
  8457  				for ( var i = 0, l = attribute.count; i < l; i ++ ) {
  8458  
  8459  					v1.x = attribute.getX( i );
  8460  					v1.y = attribute.getY( i );
  8461  					v1.z = attribute.getZ( i );
  8462  
  8463  					v1.applyMatrix3( this );
  8464  
  8465  					attribute.setXYZ( i, v1.x, v1.y, v1.z );
  8466  
  8467  				}
  8468  
  8469  				return attribute;
  8470  
  8471  			};
  8472  
  8473  		}(),
  8474  
  8475  		multiplyScalar: function ( s ) {
  8476  
  8477  			var te = this.elements;
  8478  
  8479  			te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
  8480  			te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
  8481  			te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
  8482  
  8483  			return this;
  8484  
  8485  		},
  8486  
  8487  		determinant: function () {
  8488  
  8489  			var te = this.elements;
  8490  
  8491  			var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
  8492  				d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
  8493  				g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
  8494  
  8495  			return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
  8496  
  8497  		},
  8498  
  8499  		getInverse: function ( matrix, throwOnDegenerate ) {
  8500  
  8501  			if ( matrix && matrix.isMatrix4 ) {
  8502  
  8503  				console.error( "THREE.Matrix3.getInverse no longer takes a Matrix4 argument." );
  8504  
  8505  			}
  8506  
  8507  			var me = matrix.elements,
  8508  				te = this.elements,
  8509  
  8510  				n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ],
  8511  				n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ],
  8512  				n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ],
  8513  
  8514  				t11 = n33 * n22 - n32 * n23,
  8515  				t12 = n32 * n13 - n33 * n12,
  8516  				t13 = n23 * n12 - n22 * n13,
  8517  
  8518  				det = n11 * t11 + n21 * t12 + n31 * t13;
  8519  
  8520  			if ( det === 0 ) {
  8521  
  8522  				var msg = "THREE.Matrix3.getInverse(): can't invert matrix, determinant is 0";
  8523  
  8524  				if ( throwOnDegenerate === true ) {
  8525  
  8526  					throw new Error( msg );
  8527  
  8528  				} else {
  8529  
  8530  					console.warn( msg );
  8531  
  8532  				}
  8533  
  8534  				return this.identity();
  8535  			}
  8536  
  8537  			var detInv = 1 / det;
  8538  
  8539  			te[ 0 ] = t11 * detInv;
  8540  			te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
  8541  			te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
  8542  
  8543  			te[ 3 ] = t12 * detInv;
  8544  			te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
  8545  			te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
  8546  
  8547  			te[ 6 ] = t13 * detInv;
  8548  			te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
  8549  			te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
  8550  
  8551  			return this;
  8552  
  8553  		},
  8554  
  8555  		transpose: function () {
  8556  
  8557  			var tmp, m = this.elements;
  8558  
  8559  			tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
  8560  			tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
  8561  			tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
  8562  
  8563  			return this;
  8564  
  8565  		},
  8566  
  8567  		getNormalMatrix: function ( matrix4 ) {
  8568  
  8569  			return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose();
  8570  
  8571  		},
  8572  
  8573  		transposeIntoArray: function ( r ) {
  8574  
  8575  			var m = this.elements;
  8576  
  8577  			r[ 0 ] = m[ 0 ];
  8578  			r[ 1 ] = m[ 3 ];
  8579  			r[ 2 ] = m[ 6 ];
  8580  			r[ 3 ] = m[ 1 ];
  8581  			r[ 4 ] = m[ 4 ];
  8582  			r[ 5 ] = m[ 7 ];
  8583  			r[ 6 ] = m[ 2 ];
  8584  			r[ 7 ] = m[ 5 ];
  8585  			r[ 8 ] = m[ 8 ];
  8586  
  8587  			return this;
  8588  
  8589  		},
  8590  
  8591  		fromArray: function ( array, offset ) {
  8592  
  8593  			if ( offset === undefined ) offset = 0;
  8594  
  8595  			for( var i = 0; i < 9; i ++ ) {
  8596  
  8597  				this.elements[ i ] = array[ i + offset ];
  8598  
  8599  			}
  8600  
  8601  			return this;
  8602  
  8603  		},
  8604  
  8605  		toArray: function ( array, offset ) {
  8606  
  8607  			if ( array === undefined ) array = [];
  8608  			if ( offset === undefined ) offset = 0;
  8609  
  8610  			var te = this.elements;
  8611  
  8612  			array[ offset ] = te[ 0 ];
  8613  			array[ offset + 1 ] = te[ 1 ];
  8614  			array[ offset + 2 ] = te[ 2 ];
  8615  
  8616  			array[ offset + 3 ] = te[ 3 ];
  8617  			array[ offset + 4 ] = te[ 4 ];
  8618  			array[ offset + 5 ] = te[ 5 ];
  8619  
  8620  			array[ offset + 6 ] = te[ 6 ];
  8621  			array[ offset + 7 ] = te[ 7 ];
  8622  			array[ offset + 8 ]  = te[ 8 ];
  8623  
  8624  			return array;
  8625  
  8626  		}
  8627  
  8628  	};
  8629  
  8630  	/**
  8631  	 * @author bhouston / http://clara.io
  8632  	 */
  8633  
  8634  	function Plane( normal, constant ) {
  8635  
  8636  		this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 );
  8637  		this.constant = ( constant !== undefined ) ? constant : 0;
  8638  
  8639  	}
  8640  
  8641  	Plane.prototype = {
  8642  
  8643  		constructor: Plane,
  8644  
  8645  		set: function ( normal, constant ) {
  8646  
  8647  			this.normal.copy( normal );
  8648  			this.constant = constant;
  8649  
  8650  			return this;
  8651  
  8652  		},
  8653  
  8654  		setComponents: function ( x, y, z, w ) {
  8655  
  8656  			this.normal.set( x, y, z );
  8657  			this.constant = w;
  8658  
  8659  			return this;
  8660  
  8661  		},
  8662  
  8663  		setFromNormalAndCoplanarPoint: function ( normal, point ) {
  8664  
  8665  			this.normal.copy( normal );
  8666  			this.constant = - point.dot( this.normal );	// must be this.normal, not normal, as this.normal is normalized
  8667  
  8668  			return this;
  8669  
  8670  		},
  8671  
  8672  		setFromCoplanarPoints: function () {
  8673  
  8674  			var v1 = new Vector3();
  8675  			var v2 = new Vector3();
  8676  
  8677  			return function setFromCoplanarPoints( a, b, c ) {
  8678  
  8679  				var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize();
  8680  
  8681  				// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
  8682  
  8683  				this.setFromNormalAndCoplanarPoint( normal, a );
  8684  
  8685  				return this;
  8686  
  8687  			};
  8688  
  8689  		}(),
  8690  
  8691  		clone: function () {
  8692  
  8693  			return new this.constructor().copy( this );
  8694  
  8695  		},
  8696  
  8697  		copy: function ( plane ) {
  8698  
  8699  			this.normal.copy( plane.normal );
  8700  			this.constant = plane.constant;
  8701  
  8702  			return this;
  8703  
  8704  		},
  8705  
  8706  		normalize: function () {
  8707  
  8708  			// Note: will lead to a divide by zero if the plane is invalid.
  8709  
  8710  			var inverseNormalLength = 1.0 / this.normal.length();
  8711  			this.normal.multiplyScalar( inverseNormalLength );
  8712  			this.constant *= inverseNormalLength;
  8713  
  8714  			return this;
  8715  
  8716  		},
  8717  
  8718  		negate: function () {
  8719  
  8720  			this.constant *= - 1;
  8721  			this.normal.negate();
  8722  
  8723  			return this;
  8724  
  8725  		},
  8726  
  8727  		distanceToPoint: function ( point ) {
  8728  
  8729  			return this.normal.dot( point ) + this.constant;
  8730  
  8731  		},
  8732  
  8733  		distanceToSphere: function ( sphere ) {
  8734  
  8735  			return this.distanceToPoint( sphere.center ) - sphere.radius;
  8736  
  8737  		},
  8738  
  8739  		projectPoint: function ( point, optionalTarget ) {
  8740  
  8741  			return this.orthoPoint( point, optionalTarget ).sub( point ).negate();
  8742  
  8743  		},
  8744  
  8745  		orthoPoint: function ( point, optionalTarget ) {
  8746  
  8747  			var perpendicularMagnitude = this.distanceToPoint( point );
  8748  
  8749  			var result = optionalTarget || new Vector3();
  8750  			return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude );
  8751  
  8752  		},
  8753  
  8754  		intersectLine: function () {
  8755  
  8756  			var v1 = new Vector3();
  8757  
  8758  			return function intersectLine( line, optionalTarget ) {
  8759  
  8760  				var result = optionalTarget || new Vector3();
  8761  
  8762  				var direction = line.delta( v1 );
  8763  
  8764  				var denominator = this.normal.dot( direction );
  8765  
  8766  				if ( denominator === 0 ) {
  8767  
  8768  					// line is coplanar, return origin
  8769  					if ( this.distanceToPoint( line.start ) === 0 ) {
  8770  
  8771  						return result.copy( line.start );
  8772  
  8773  					}
  8774  
  8775  					// Unsure if this is the correct method to handle this case.
  8776  					return undefined;
  8777  
  8778  				}
  8779  
  8780  				var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
  8781  
  8782  				if ( t < 0 || t > 1 ) {
  8783  
  8784  					return undefined;
  8785  
  8786  				}
  8787  
  8788  				return result.copy( direction ).multiplyScalar( t ).add( line.start );
  8789  
  8790  			};
  8791  
  8792  		}(),
  8793  
  8794  		intersectsLine: function ( line ) {
  8795  
  8796  			// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
  8797  
  8798  			var startSign = this.distanceToPoint( line.start );
  8799  			var endSign = this.distanceToPoint( line.end );
  8800  
  8801  			return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
  8802  
  8803  		},
  8804  
  8805  		intersectsBox: function ( box ) {
  8806  
  8807  			return box.intersectsPlane( this );
  8808  
  8809  		},
  8810  
  8811  		intersectsSphere: function ( sphere ) {
  8812  
  8813  			return sphere.intersectsPlane( this );
  8814  
  8815  		},
  8816  
  8817  		coplanarPoint: function ( optionalTarget ) {
  8818  
  8819  			var result = optionalTarget || new Vector3();
  8820  			return result.copy( this.normal ).multiplyScalar( - this.constant );
  8821  
  8822  		},
  8823  
  8824  		applyMatrix4: function () {
  8825  
  8826  			var v1 = new Vector3();
  8827  			var m1 = new Matrix3();
  8828  
  8829  			return function applyMatrix4( matrix, optionalNormalMatrix ) {
  8830  
  8831  				var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix );
  8832  
  8833  				// transform normal based on theory here:
  8834  				// http://www.songho.ca/opengl/gl_normaltransform.html
  8835  				var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix );
  8836  				var normal = this.normal.applyMatrix3( normalMatrix ).normalize();
  8837  
  8838  				// recalculate constant (like in setFromNormalAndCoplanarPoint)
  8839  				this.constant = - referencePoint.dot( normal );
  8840  
  8841  				return this;
  8842  
  8843  			};
  8844  
  8845  		}(),
  8846  
  8847  		translate: function ( offset ) {
  8848  
  8849  			this.constant = this.constant - offset.dot( this.normal );
  8850  
  8851  			return this;
  8852  
  8853  		},
  8854  
  8855  		equals: function ( plane ) {
  8856  
  8857  			return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );
  8858  
  8859  		}
  8860  
  8861  	};
  8862  
  8863  	/**
  8864  	 * @author mrdoob / http://mrdoob.com/
  8865  	 * @author alteredq / http://alteredqualia.com/
  8866  	 * @author bhouston / http://clara.io
  8867  	 */
  8868  
  8869  	function Frustum( p0, p1, p2, p3, p4, p5 ) {
  8870  
  8871  		this.planes = [
  8872  
  8873  			( p0 !== undefined ) ? p0 : new Plane(),
  8874  			( p1 !== undefined ) ? p1 : new Plane(),
  8875  			( p2 !== undefined ) ? p2 : new Plane(),
  8876  			( p3 !== undefined ) ? p3 : new Plane(),
  8877  			( p4 !== undefined ) ? p4 : new Plane(),
  8878  			( p5 !== undefined ) ? p5 : new Plane()
  8879  
  8880  		];
  8881  
  8882  	}
  8883  
  8884  	Frustum.prototype = {
  8885  
  8886  		constructor: Frustum,
  8887  
  8888  		set: function ( p0, p1, p2, p3, p4, p5 ) {
  8889  
  8890  			var planes = this.planes;
  8891  
  8892  			planes[ 0 ].copy( p0 );
  8893  			planes[ 1 ].copy( p1 );
  8894  			planes[ 2 ].copy( p2 );
  8895  			planes[ 3 ].copy( p3 );
  8896  			planes[ 4 ].copy( p4 );
  8897  			planes[ 5 ].copy( p5 );
  8898  
  8899  			return this;
  8900  
  8901  		},
  8902  
  8903  		clone: function () {
  8904  
  8905  			return new this.constructor().copy( this );
  8906  
  8907  		},
  8908  
  8909  		copy: function ( frustum ) {
  8910  
  8911  			var planes = this.planes;
  8912  
  8913  			for ( var i = 0; i < 6; i ++ ) {
  8914  
  8915  				planes[ i ].copy( frustum.planes[ i ] );
  8916  
  8917  			}
  8918  
  8919  			return this;
  8920  
  8921  		},
  8922  
  8923  		setFromMatrix: function ( m ) {
  8924  
  8925  			var planes = this.planes;
  8926  			var me = m.elements;
  8927  			var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
  8928  			var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
  8929  			var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
  8930  			var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
  8931  
  8932  			planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
  8933  			planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
  8934  			planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
  8935  			planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
  8936  			planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
  8937  			planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
  8938  
  8939  			return this;
  8940  
  8941  		},
  8942  
  8943  		intersectsObject: function () {
  8944  
  8945  			var sphere = new Sphere();
  8946  
  8947  			return function intersectsObject( object ) {
  8948  
  8949  				var geometry = object.geometry;
  8950  
  8951  				if ( geometry.boundingSphere === null )
  8952  					geometry.computeBoundingSphere();
  8953  
  8954  				sphere.copy( geometry.boundingSphere )
  8955  					.applyMatrix4( object.matrixWorld );
  8956  
  8957  				return this.intersectsSphere( sphere );
  8958  
  8959  			};
  8960  
  8961  		}(),
  8962  
  8963  		intersectsSprite: function () {
  8964  
  8965  			var sphere = new Sphere();
  8966  
  8967  			return function intersectsSprite( sprite ) {
  8968  
  8969  				sphere.center.set( 0, 0, 0 );
  8970  				sphere.radius = 0.7071067811865476;
  8971  				sphere.applyMatrix4( sprite.matrixWorld );
  8972  
  8973  				return this.intersectsSphere( sphere );
  8974  
  8975  			};
  8976  
  8977  		}(),
  8978  
  8979  		intersectsSphere: function ( sphere ) {
  8980  
  8981  			var planes = this.planes;
  8982  			var center = sphere.center;
  8983  			var negRadius = - sphere.radius;
  8984  
  8985  			for ( var i = 0; i < 6; i ++ ) {
  8986  
  8987  				var distance = planes[ i ].distanceToPoint( center );
  8988  
  8989  				if ( distance < negRadius ) {
  8990  
  8991  					return false;
  8992  
  8993  				}
  8994  
  8995  			}
  8996  
  8997  			return true;
  8998  
  8999  		},
  9000  
  9001  		intersectsBox: function () {
  9002  
  9003  			var p1 = new Vector3(),
  9004  				p2 = new Vector3();
  9005  
  9006  			return function intersectsBox( box ) {
  9007  
  9008  				var planes = this.planes;
  9009  
  9010  				for ( var i = 0; i < 6 ; i ++ ) {
  9011  
  9012  					var plane = planes[ i ];
  9013  
  9014  					p1.x = plane.normal.x > 0 ? box.min.x : box.max.x;
  9015  					p2.x = plane.normal.x > 0 ? box.max.x : box.min.x;
  9016  					p1.y = plane.normal.y > 0 ? box.min.y : box.max.y;
  9017  					p2.y = plane.normal.y > 0 ? box.max.y : box.min.y;
  9018  					p1.z = plane.normal.z > 0 ? box.min.z : box.max.z;
  9019  					p2.z = plane.normal.z > 0 ? box.max.z : box.min.z;
  9020  
  9021  					var d1 = plane.distanceToPoint( p1 );
  9022  					var d2 = plane.distanceToPoint( p2 );
  9023  
  9024  					// if both outside plane, no intersection
  9025  
  9026  					if ( d1 < 0 && d2 < 0 ) {
  9027  
  9028  						return false;
  9029  
  9030  					}
  9031  
  9032  				}
  9033  
  9034  				return true;
  9035  
  9036  			};
  9037  
  9038  		}(),
  9039  
  9040  
  9041  		containsPoint: function ( point ) {
  9042  
  9043  			var planes = this.planes;
  9044  
  9045  			for ( var i = 0; i < 6; i ++ ) {
  9046  
  9047  				if ( planes[ i ].distanceToPoint( point ) < 0 ) {
  9048  
  9049  					return false;
  9050  
  9051  				}
  9052  
  9053  			}
  9054  
  9055  			return true;
  9056  
  9057  		}
  9058  
  9059  	};
  9060  
  9061  	/**
  9062  	 * @author alteredq / http://alteredqualia.com/
  9063  	 * @author mrdoob / http://mrdoob.com/
  9064  	 */
  9065  
  9066  	function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) {
  9067  
  9068  		var _gl = _renderer.context,
  9069  		_state = _renderer.state,
  9070  		_frustum = new Frustum(),
  9071  		_projScreenMatrix = new Matrix4(),
  9072  
  9073  		_lightShadows = _lights.shadows,
  9074  
  9075  		_shadowMapSize = new Vector2(),
  9076  		_maxShadowMapSize = new Vector2( capabilities.maxTextureSize, capabilities.maxTextureSize ),
  9077  
  9078  		_lookTarget = new Vector3(),
  9079  		_lightPositionWorld = new Vector3(),
  9080  
  9081  		_renderList = [],
  9082  
  9083  		_MorphingFlag = 1,
  9084  		_SkinningFlag = 2,
  9085  
  9086  		_NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,
  9087  
  9088  		_depthMaterials = new Array( _NumberOfMaterialVariants ),
  9089  		_distanceMaterials = new Array( _NumberOfMaterialVariants ),
  9090  
  9091  		_materialCache = {};
  9092  
  9093  		var cubeDirections = [
  9094  			new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
  9095  			new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
  9096  		];
  9097  
  9098  		var cubeUps = [
  9099  			new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
  9100  			new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ),	new Vector3( 0, 0, - 1 )
  9101  		];
  9102  
  9103  		var cube2DViewPorts = [
  9104  			new Vector4(), new Vector4(), new Vector4(),
  9105  			new Vector4(), new Vector4(), new Vector4()
  9106  		];
  9107  
  9108  		// init
  9109  
  9110  		var depthMaterialTemplate = new MeshDepthMaterial();
  9111  		depthMaterialTemplate.depthPacking = RGBADepthPacking;
  9112  		depthMaterialTemplate.clipping = true;
  9113  
  9114  		var distanceShader = ShaderLib[ "distanceRGBA" ];
  9115  		var distanceUniforms = UniformsUtils.clone( distanceShader.uniforms );
  9116  
  9117  		for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) {
  9118  
  9119  			var useMorphing = ( i & _MorphingFlag ) !== 0;
  9120  			var useSkinning = ( i & _SkinningFlag ) !== 0;
  9121  
  9122  			var depthMaterial = depthMaterialTemplate.clone();
  9123  			depthMaterial.morphTargets = useMorphing;
  9124  			depthMaterial.skinning = useSkinning;
  9125  
  9126  			_depthMaterials[ i ] = depthMaterial;
  9127  
  9128  			var distanceMaterial = new ShaderMaterial( {
  9129  				defines: {
  9130  					'USE_SHADOWMAP': ''
  9131  				},
  9132  				uniforms: distanceUniforms,
  9133  				vertexShader: distanceShader.vertexShader,
  9134  				fragmentShader: distanceShader.fragmentShader,
  9135  				morphTargets: useMorphing,
  9136  				skinning: useSkinning,
  9137  				clipping: true
  9138  			} );
  9139  
  9140  			_distanceMaterials[ i ] = distanceMaterial;
  9141  
  9142  		}
  9143  
  9144  		//
  9145  
  9146  		var scope = this;
  9147  
  9148  		this.enabled = false;
  9149  
  9150  		this.autoUpdate = true;
  9151  		this.needsUpdate = false;
  9152  
  9153  		this.type = PCFShadowMap;
  9154  
  9155  		this.renderReverseSided = true;
  9156  		this.renderSingleSided = true;
  9157  
  9158  		this.render = function ( scene, camera ) {
  9159  
  9160  			if ( scope.enabled === false ) return;
  9161  			if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
  9162  
  9163  			if ( _lightShadows.length === 0 ) return;
  9164  
  9165  			// Set GL state for depth map.
  9166  			_state.buffers.color.setClear( 1, 1, 1, 1 );
  9167  			_state.disable( _gl.BLEND );
  9168  			_state.setDepthTest( true );
  9169  			_state.setScissorTest( false );
  9170  
  9171  			// render depth map
  9172  
  9173  			var faceCount, isPointLight;
  9174  
  9175  			for ( var i = 0, il = _lightShadows.length; i < il; i ++ ) {
  9176  
  9177  				var light = _lightShadows[ i ];
  9178  				var shadow = light.shadow;
  9179  
  9180  				if ( shadow === undefined ) {
  9181  
  9182  					console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
  9183  					continue;
  9184  
  9185  				}
  9186  
  9187  				var shadowCamera = shadow.camera;
  9188  
  9189  				_shadowMapSize.copy( shadow.mapSize );
  9190  				_shadowMapSize.min( _maxShadowMapSize );
  9191  
  9192  				if ( light && light.isPointLight ) {
  9193  
  9194  					faceCount = 6;
  9195  					isPointLight = true;
  9196  
  9197  					var vpWidth = _shadowMapSize.x;
  9198  					var vpHeight = _shadowMapSize.y;
  9199  
  9200  					// These viewports map a cube-map onto a 2D texture with the
  9201  					// following orientation:
  9202  					//
  9203  					//  xzXZ
  9204  					//   y Y
  9205  					//
  9206  					// X - Positive x direction
  9207  					// x - Negative x direction
  9208  					// Y - Positive y direction
  9209  					// y - Negative y direction
  9210  					// Z - Positive z direction
  9211  					// z - Negative z direction
  9212  
  9213  					// positive X
  9214  					cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight );
  9215  					// negative X
  9216  					cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight );
  9217  					// positive Z
  9218  					cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight );
  9219  					// negative Z
  9220  					cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight );
  9221  					// positive Y
  9222  					cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight );
  9223  					// negative Y
  9224  					cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight );
  9225  
  9226  					_shadowMapSize.x *= 4.0;
  9227  					_shadowMapSize.y *= 2.0;
  9228  
  9229  				} else {
  9230  
  9231  					faceCount = 1;
  9232  					isPointLight = false;
  9233  
  9234  				}
  9235  
  9236  				if ( shadow.map === null ) {
  9237  
  9238  					var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };
  9239  
  9240  					shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
  9241  
  9242  					shadowCamera.updateProjectionMatrix();
  9243  
  9244  				}
  9245  
  9246  				if ( shadow.isSpotLightShadow ) {
  9247  
  9248  					shadow.update( light );
  9249  
  9250  				}
  9251  
  9252  				// TODO (abelnation / sam-g-steel): is this needed?
  9253  				if (shadow && shadow.isRectAreaLightShadow ) {
  9254  
  9255  					shadow.update( light );
  9256  
  9257  				}
  9258  
  9259  				var shadowMap = shadow.map;
  9260  				var shadowMatrix = shadow.matrix;
  9261  
  9262  				_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
  9263  				shadowCamera.position.copy( _lightPositionWorld );
  9264  
  9265  				_renderer.setRenderTarget( shadowMap );
  9266  				_renderer.clear();
  9267  
  9268  				// render shadow map for each cube face (if omni-directional) or
  9269  				// run a single pass if not
  9270  
  9271  				for ( var face = 0; face < faceCount; face ++ ) {
  9272  
  9273  					if ( isPointLight ) {
  9274  
  9275  						_lookTarget.copy( shadowCamera.position );
  9276  						_lookTarget.add( cubeDirections[ face ] );
  9277  						shadowCamera.up.copy( cubeUps[ face ] );
  9278  						shadowCamera.lookAt( _lookTarget );
  9279  
  9280  						var vpDimensions = cube2DViewPorts[ face ];
  9281  						_state.viewport( vpDimensions );
  9282  
  9283  					} else {
  9284  
  9285  						_lookTarget.setFromMatrixPosition( light.target.matrixWorld );
  9286  						shadowCamera.lookAt( _lookTarget );
  9287  
  9288  					}
  9289  
  9290  					shadowCamera.updateMatrixWorld();
  9291  					shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld );
  9292  
  9293  					// compute shadow matrix
  9294  
  9295  					shadowMatrix.set(
  9296  						0.5, 0.0, 0.0, 0.5,
  9297  						0.0, 0.5, 0.0, 0.5,
  9298  						0.0, 0.0, 0.5, 0.5,
  9299  						0.0, 0.0, 0.0, 1.0
  9300  					);
  9301  
  9302  					shadowMatrix.multiply( shadowCamera.projectionMatrix );
  9303  					shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
  9304  
  9305  					// update camera matrices and frustum
  9306  
  9307  					_projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
  9308  					_frustum.setFromMatrix( _projScreenMatrix );
  9309  
  9310  					// set object matrices & frustum culling
  9311  
  9312  					_renderList.length = 0;
  9313  
  9314  					projectObject( scene, camera, shadowCamera );
  9315  
  9316  					// render shadow map
  9317  					// render regular objects
  9318  
  9319  					for ( var j = 0, jl = _renderList.length; j < jl; j ++ ) {
  9320  
  9321  						var object = _renderList[ j ];
  9322  						var geometry = _objects.update( object );
  9323  						var material = object.material;
  9324  
  9325  						if ( material && material.isMultiMaterial ) {
  9326  
  9327  							var groups = geometry.groups;
  9328  							var materials = material.materials;
  9329  
  9330  							for ( var k = 0, kl = groups.length; k < kl; k ++ ) {
  9331  
  9332  								var group = groups[ k ];
  9333  								var groupMaterial = materials[ group.materialIndex ];
  9334  
  9335  								if ( groupMaterial.visible === true ) {
  9336  
  9337  									var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld );
  9338  									_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
  9339  
  9340  								}
  9341  
  9342  							}
  9343  
  9344  						} else {
  9345  
  9346  							var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld );
  9347  							_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
  9348  
  9349  						}
  9350  
  9351  					}
  9352  
  9353  				}
  9354  
  9355  			}
  9356  
  9357  			// Restore GL state.
  9358  			var clearColor = _renderer.getClearColor(),
  9359  			clearAlpha = _renderer.getClearAlpha();
  9360  			_renderer.setClearColor( clearColor, clearAlpha );
  9361  
  9362  			scope.needsUpdate = false;
  9363  
  9364  		};
  9365  
  9366  		function getDepthMaterial( object, material, isPointLight, lightPositionWorld ) {
  9367  
  9368  			var geometry = object.geometry;
  9369  
  9370  			var result = null;
  9371  
  9372  			var materialVariants = _depthMaterials;
  9373  			var customMaterial = object.customDepthMaterial;
  9374  
  9375  			if ( isPointLight ) {
  9376  
  9377  				materialVariants = _distanceMaterials;
  9378  				customMaterial = object.customDistanceMaterial;
  9379  
  9380  			}
  9381  
  9382  			if ( ! customMaterial ) {
  9383  
  9384  				var useMorphing = false;
  9385  
  9386  				if ( material.morphTargets ) {
  9387  
  9388  					if ( geometry && geometry.isBufferGeometry ) {
  9389  
  9390  						useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;
  9391  
  9392  					} else if ( geometry && geometry.isGeometry ) {
  9393  
  9394  						useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0;
  9395  
  9396  					}
  9397  
  9398  				}
  9399  
  9400  				var useSkinning = object.isSkinnedMesh && material.skinning;
  9401  
  9402  				var variantIndex = 0;
  9403  
  9404  				if ( useMorphing ) variantIndex |= _MorphingFlag;
  9405  				if ( useSkinning ) variantIndex |= _SkinningFlag;
  9406  
  9407  				result = materialVariants[ variantIndex ];
  9408  
  9409  			} else {
  9410  
  9411  				result = customMaterial;
  9412  
  9413  			}
  9414  
  9415  			if ( _renderer.localClippingEnabled &&
  9416  				 material.clipShadows === true &&
  9417  					material.clippingPlanes.length !== 0 ) {
  9418  
  9419  				// in this case we need a unique material instance reflecting the
  9420  				// appropriate state
  9421  
  9422  				var keyA = result.uuid, keyB = material.uuid;
  9423  
  9424  				var materialsForVariant = _materialCache[ keyA ];
  9425  
  9426  				if ( materialsForVariant === undefined ) {
  9427  
  9428  					materialsForVariant = {};
  9429  					_materialCache[ keyA ] = materialsForVariant;
  9430  
  9431  				}
  9432  
  9433  				var cachedMaterial = materialsForVariant[ keyB ];
  9434  
  9435  				if ( cachedMaterial === undefined ) {
  9436  
  9437  					cachedMaterial = result.clone();
  9438  					materialsForVariant[ keyB ] = cachedMaterial;
  9439  
  9440  				}
  9441  
  9442  				result = cachedMaterial;
  9443  
  9444  			}
  9445  
  9446  			result.visible = material.visible;
  9447  			result.wireframe = material.wireframe;
  9448  
  9449  			var side = material.side;
  9450  
  9451  			if ( scope.renderSingleSided && side == DoubleSide ) {
  9452  
  9453  				side = FrontSide;
  9454  
  9455  			}
  9456  
  9457  			if ( scope.renderReverseSided ) {
  9458  
  9459  				if ( side === FrontSide ) side = BackSide;
  9460  				else if ( side === BackSide ) side = FrontSide;
  9461  
  9462  			}
  9463  
  9464  			result.side = side;
  9465  
  9466  			result.clipShadows = material.clipShadows;
  9467  			result.clippingPlanes = material.clippingPlanes;
  9468  
  9469  			result.wireframeLinewidth = material.wireframeLinewidth;
  9470  			result.linewidth = material.linewidth;
  9471  
  9472  			if ( isPointLight && result.uniforms.lightPos !== undefined ) {
  9473  
  9474  				result.uniforms.lightPos.value.copy( lightPositionWorld );
  9475  
  9476  			}
  9477  
  9478  			return result;
  9479  
  9480  		}
  9481  
  9482  		function projectObject( object, camera, shadowCamera ) {
  9483  
  9484  			if ( object.visible === false ) return;
  9485  
  9486  			var visible = ( object.layers.mask & camera.layers.mask ) !== 0;
  9487  
  9488  			if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
  9489  
  9490  				if ( object.castShadow && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) {
  9491  
  9492  					var material = object.material;
  9493  
  9494  					if ( material.visible === true ) {
  9495  
  9496  						object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
  9497  						_renderList.push( object );
  9498  
  9499  					}
  9500  
  9501  				}
  9502  
  9503  			}
  9504  
  9505  			var children = object.children;
  9506  
  9507  			for ( var i = 0, l = children.length; i < l; i ++ ) {
  9508  
  9509  				projectObject( children[ i ], camera, shadowCamera );
  9510  
  9511  			}
  9512  
  9513  		}
  9514  
  9515  	}
  9516  
  9517  	/**
  9518  	 * @author bhouston / http://clara.io
  9519  	 */
  9520  
  9521  	function Ray( origin, direction ) {
  9522  
  9523  		this.origin = ( origin !== undefined ) ? origin : new Vector3();
  9524  		this.direction = ( direction !== undefined ) ? direction : new Vector3();
  9525  
  9526  	}
  9527  
  9528  	Ray.prototype = {
  9529  
  9530  		constructor: Ray,
  9531  
  9532  		set: function ( origin, direction ) {
  9533  
  9534  			this.origin.copy( origin );
  9535  			this.direction.copy( direction );
  9536  
  9537  			return this;
  9538  
  9539  		},
  9540  
  9541  		clone: function () {
  9542  
  9543  			return new this.constructor().copy( this );
  9544  
  9545  		},
  9546  
  9547  		copy: function ( ray ) {
  9548  
  9549  			this.origin.copy( ray.origin );
  9550  			this.direction.copy( ray.direction );
  9551  
  9552  			return this;
  9553  
  9554  		},
  9555  
  9556  		at: function ( t, optionalTarget ) {
  9557  
  9558  			var result = optionalTarget || new Vector3();
  9559  
  9560  			return result.copy( this.direction ).multiplyScalar( t ).add( this.origin );
  9561  
  9562  		},
  9563  
  9564  		lookAt: function ( v ) {
  9565  
  9566  			this.direction.copy( v ).sub( this.origin ).normalize();
  9567  
  9568  			return this;
  9569  
  9570  		},
  9571  
  9572  		recast: function () {
  9573  
  9574  			var v1 = new Vector3();
  9575  
  9576  			return function recast( t ) {
  9577  
  9578  				this.origin.copy( this.at( t, v1 ) );
  9579  
  9580  				return this;
  9581  
  9582  			};
  9583  
  9584  		}(),
  9585  
  9586  		closestPointToPoint: function ( point, optionalTarget ) {
  9587  
  9588  			var result = optionalTarget || new Vector3();
  9589  			result.subVectors( point, this.origin );
  9590  			var directionDistance = result.dot( this.direction );
  9591  
  9592  			if ( directionDistance < 0 ) {
  9593  
  9594  				return result.copy( this.origin );
  9595  
  9596  			}
  9597  
  9598  			return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
  9599  
  9600  		},
  9601  
  9602  		distanceToPoint: function ( point ) {
  9603  
  9604  			return Math.sqrt( this.distanceSqToPoint( point ) );
  9605  
  9606  		},
  9607  
  9608  		distanceSqToPoint: function () {
  9609  
  9610  			var v1 = new Vector3();
  9611  
  9612  			return function distanceSqToPoint( point ) {
  9613  
  9614  				var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );
  9615  
  9616  				// point behind the ray
  9617  
  9618  				if ( directionDistance < 0 ) {
  9619  
  9620  					return this.origin.distanceToSquared( point );
  9621  
  9622  				}
  9623  
  9624  				v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
  9625  
  9626  				return v1.distanceToSquared( point );
  9627  
  9628  			};
  9629  
  9630  		}(),
  9631  
  9632  		distanceSqToSegment: function () {
  9633  
  9634  			var segCenter = new Vector3();
  9635  			var segDir = new Vector3();
  9636  			var diff = new Vector3();
  9637  
  9638  			return function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
  9639  
  9640  				// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
  9641  				// It returns the min distance between the ray and the segment
  9642  				// defined by v0 and v1
  9643  				// It can also set two optional targets :
  9644  				// - The closest point on the ray
  9645  				// - The closest point on the segment
  9646  
  9647  				segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
  9648  				segDir.copy( v1 ).sub( v0 ).normalize();
  9649  				diff.copy( this.origin ).sub( segCenter );
  9650  
  9651  				var segExtent = v0.distanceTo( v1 ) * 0.5;
  9652  				var a01 = - this.direction.dot( segDir );
  9653  				var b0 = diff.dot( this.direction );
  9654  				var b1 = - diff.dot( segDir );
  9655  				var c = diff.lengthSq();
  9656  				var det = Math.abs( 1 - a01 * a01 );
  9657  				var s0, s1, sqrDist, extDet;
  9658  
  9659  				if ( det > 0 ) {
  9660  
  9661  					// The ray and segment are not parallel.
  9662  
  9663  					s0 = a01 * b1 - b0;
  9664  					s1 = a01 * b0 - b1;
  9665  					extDet = segExtent * det;
  9666  
  9667  					if ( s0 >= 0 ) {
  9668  
  9669  						if ( s1 >= - extDet ) {
  9670  
  9671  							if ( s1 <= extDet ) {
  9672  
  9673  								// region 0
  9674  								// Minimum at interior points of ray and segment.
  9675  
  9676  								var invDet = 1 / det;
  9677  								s0 *= invDet;
  9678  								s1 *= invDet;
  9679  								sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
  9680  
  9681  							} else {
  9682  
  9683  								// region 1
  9684  
  9685  								s1 = segExtent;
  9686  								s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
  9687  								sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  9688  
  9689  							}
  9690  
  9691  						} else {
  9692  
  9693  							// region 5
  9694  
  9695  							s1 = - segExtent;
  9696  							s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
  9697  							sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  9698  
  9699  						}
  9700  
  9701  					} else {
  9702  
  9703  						if ( s1 <= - extDet ) {
  9704  
  9705  							// region 4
  9706  
  9707  							s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
  9708  							s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
  9709  							sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  9710  
  9711  						} else if ( s1 <= extDet ) {
  9712  
  9713  							// region 3
  9714  
  9715  							s0 = 0;
  9716  							s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
  9717  							sqrDist = s1 * ( s1 + 2 * b1 ) + c;
  9718  
  9719  						} else {
  9720  
  9721  							// region 2
  9722  
  9723  							s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
  9724  							s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
  9725  							sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  9726  
  9727  						}
  9728  
  9729  					}
  9730  
  9731  				} else {
  9732  
  9733  					// Ray and segment are parallel.
  9734  
  9735  					s1 = ( a01 > 0 ) ? - segExtent : segExtent;
  9736  					s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
  9737  					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
  9738  
  9739  				}
  9740  
  9741  				if ( optionalPointOnRay ) {
  9742  
  9743  					optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );
  9744  
  9745  				}
  9746  
  9747  				if ( optionalPointOnSegment ) {
  9748  
  9749  					optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter );
  9750  
  9751  				}
  9752  
  9753  				return sqrDist;
  9754  
  9755  			};
  9756  
  9757  		}(),
  9758  
  9759  		intersectSphere: function () {
  9760  
  9761  			var v1 = new Vector3();
  9762  
  9763  			return function intersectSphere( sphere, optionalTarget ) {
  9764  
  9765  				v1.subVectors( sphere.center, this.origin );
  9766  				var tca = v1.dot( this.direction );
  9767  				var d2 = v1.dot( v1 ) - tca * tca;
  9768  				var radius2 = sphere.radius * sphere.radius;
  9769  
  9770  				if ( d2 > radius2 ) return null;
  9771  
  9772  				var thc = Math.sqrt( radius2 - d2 );
  9773  
  9774  				// t0 = first intersect point - entrance on front of sphere
  9775  				var t0 = tca - thc;
  9776  
  9777  				// t1 = second intersect point - exit point on back of sphere
  9778  				var t1 = tca + thc;
  9779  
  9780  				// test to see if both t0 and t1 are behind the ray - if so, return null
  9781  				if ( t0 < 0 && t1 < 0 ) return null;
  9782  
  9783  				// test to see if t0 is behind the ray:
  9784  				// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
  9785  				// in order to always return an intersect point that is in front of the ray.
  9786  				if ( t0 < 0 ) return this.at( t1, optionalTarget );
  9787  
  9788  				// else t0 is in front of the ray, so return the first collision point scaled by t0
  9789  				return this.at( t0, optionalTarget );
  9790  
  9791  			};
  9792  
  9793  		}(),
  9794  
  9795  		intersectsSphere: function ( sphere ) {
  9796  
  9797  			return this.distanceToPoint( sphere.center ) <= sphere.radius;
  9798  
  9799  		},
  9800  
  9801  		distanceToPlane: function ( plane ) {
  9802  
  9803  			var denominator = plane.normal.dot( this.direction );
  9804  
  9805  			if ( denominator === 0 ) {
  9806  
  9807  				// line is coplanar, return origin
  9808  				if ( plane.distanceToPoint( this.origin ) === 0 ) {
  9809  
  9810  					return 0;
  9811  
  9812  				}
  9813  
  9814  				// Null is preferable to undefined since undefined means.... it is undefined
  9815  
  9816  				return null;
  9817  
  9818  			}
  9819  
  9820  			var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
  9821  
  9822  			// Return if the ray never intersects the plane
  9823  
  9824  			return t >= 0 ? t :  null;
  9825  
  9826  		},
  9827  
  9828  		intersectPlane: function ( plane, optionalTarget ) {
  9829  
  9830  			var t = this.distanceToPlane( plane );
  9831  
  9832  			if ( t === null ) {
  9833  
  9834  				return null;
  9835  
  9836  			}
  9837  
  9838  			return this.at( t, optionalTarget );
  9839  
  9840  		},
  9841  
  9842  
  9843  
  9844  		intersectsPlane: function ( plane ) {
  9845  
  9846  			// check if the ray lies on the plane first
  9847  
  9848  			var distToPoint = plane.distanceToPoint( this.origin );
  9849  
  9850  			if ( distToPoint === 0 ) {
  9851  
  9852  				return true;
  9853  
  9854  			}
  9855  
  9856  			var denominator = plane.normal.dot( this.direction );
  9857  
  9858  			if ( denominator * distToPoint < 0 ) {
  9859  
  9860  				return true;
  9861  
  9862  			}
  9863  
  9864  			// ray origin is behind the plane (and is pointing behind it)
  9865  
  9866  			return false;
  9867  
  9868  		},
  9869  
  9870  		intersectBox: function ( box, optionalTarget ) {
  9871  
  9872  			var tmin, tmax, tymin, tymax, tzmin, tzmax;
  9873  
  9874  			var invdirx = 1 / this.direction.x,
  9875  				invdiry = 1 / this.direction.y,
  9876  				invdirz = 1 / this.direction.z;
  9877  
  9878  			var origin = this.origin;
  9879  
  9880  			if ( invdirx >= 0 ) {
  9881  
  9882  				tmin = ( box.min.x - origin.x ) * invdirx;
  9883  				tmax = ( box.max.x - origin.x ) * invdirx;
  9884  
  9885  			} else {
  9886  
  9887  				tmin = ( box.max.x - origin.x ) * invdirx;
  9888  				tmax = ( box.min.x - origin.x ) * invdirx;
  9889  
  9890  			}
  9891  
  9892  			if ( invdiry >= 0 ) {
  9893  
  9894  				tymin = ( box.min.y - origin.y ) * invdiry;
  9895  				tymax = ( box.max.y - origin.y ) * invdiry;
  9896  
  9897  			} else {
  9898  
  9899  				tymin = ( box.max.y - origin.y ) * invdiry;
  9900  				tymax = ( box.min.y - origin.y ) * invdiry;
  9901  
  9902  			}
  9903  
  9904  			if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
  9905  
  9906  			// These lines also handle the case where tmin or tmax is NaN
  9907  			// (result of 0 * Infinity). x !== x returns true if x is NaN
  9908  
  9909  			if ( tymin > tmin || tmin !== tmin ) tmin = tymin;
  9910  
  9911  			if ( tymax < tmax || tmax !== tmax ) tmax = tymax;
  9912  
  9913  			if ( invdirz >= 0 ) {
  9914  
  9915  				tzmin = ( box.min.z - origin.z ) * invdirz;
  9916  				tzmax = ( box.max.z - origin.z ) * invdirz;
  9917  
  9918  			} else {
  9919  
  9920  				tzmin = ( box.max.z - origin.z ) * invdirz;
  9921  				tzmax = ( box.min.z - origin.z ) * invdirz;
  9922  
  9923  			}
  9924  
  9925  			if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
  9926  
  9927  			if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
  9928  
  9929  			if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
  9930  
  9931  			//return point closest to the ray (positive side)
  9932  
  9933  			if ( tmax < 0 ) return null;
  9934  
  9935  			return this.at( tmin >= 0 ? tmin : tmax, optionalTarget );
  9936  
  9937  		},
  9938  
  9939  		intersectsBox: ( function () {
  9940  
  9941  			var v = new Vector3();
  9942  
  9943  			return function intersectsBox( box ) {
  9944  
  9945  				return this.intersectBox( box, v ) !== null;
  9946  
  9947  			};
  9948  
  9949  		} )(),
  9950  
  9951  		intersectTriangle: function () {
  9952  
  9953  			// Compute the offset origin, edges, and normal.
  9954  			var diff = new Vector3();
  9955  			var edge1 = new Vector3();
  9956  			var edge2 = new Vector3();
  9957  			var normal = new Vector3();
  9958  
  9959  			return function intersectTriangle( a, b, c, backfaceCulling, optionalTarget ) {
  9960  
  9961  				// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
  9962  
  9963  				edge1.subVectors( b, a );
  9964  				edge2.subVectors( c, a );
  9965  				normal.crossVectors( edge1, edge2 );
  9966  
  9967  				// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
  9968  				// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
  9969  				//   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
  9970  				//   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
  9971  				//   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
  9972  				var DdN = this.direction.dot( normal );
  9973  				var sign;
  9974  
  9975  				if ( DdN > 0 ) {
  9976  
  9977  					if ( backfaceCulling ) return null;
  9978  					sign = 1;
  9979  
  9980  				} else if ( DdN < 0 ) {
  9981  
  9982  					sign = - 1;
  9983  					DdN = - DdN;
  9984  
  9985  				} else {
  9986  
  9987  					return null;
  9988  
  9989  				}
  9990  
  9991  				diff.subVectors( this.origin, a );
  9992  				var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );
  9993  
  9994  				// b1 < 0, no intersection
  9995  				if ( DdQxE2 < 0 ) {
  9996  
  9997  					return null;
  9998  
  9999  				}
 10000  
 10001  				var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );
 10002  
 10003  				// b2 < 0, no intersection
 10004  				if ( DdE1xQ < 0 ) {
 10005  
 10006  					return null;
 10007  
 10008  				}
 10009  
 10010  				// b1+b2 > 1, no intersection
 10011  				if ( DdQxE2 + DdE1xQ > DdN ) {
 10012  
 10013  					return null;
 10014  
 10015  				}
 10016  
 10017  				// Line intersects triangle, check if ray does.
 10018  				var QdN = - sign * diff.dot( normal );
 10019  
 10020  				// t < 0, no intersection
 10021  				if ( QdN < 0 ) {
 10022  
 10023  					return null;
 10024  
 10025  				}
 10026  
 10027  				// Ray intersects triangle.
 10028  				return this.at( QdN / DdN, optionalTarget );
 10029  
 10030  			};
 10031  
 10032  		}(),
 10033  
 10034  		applyMatrix4: function ( matrix4 ) {
 10035  
 10036  			this.direction.add( this.origin ).applyMatrix4( matrix4 );
 10037  			this.origin.applyMatrix4( matrix4 );
 10038  			this.direction.sub( this.origin );
 10039  			this.direction.normalize();
 10040  
 10041  			return this;
 10042  
 10043  		},
 10044  
 10045  		equals: function ( ray ) {
 10046  
 10047  			return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
 10048  
 10049  		}
 10050  
 10051  	};
 10052  
 10053  	/**
 10054  	 * @author mrdoob / http://mrdoob.com/
 10055  	 * @author WestLangley / http://github.com/WestLangley
 10056  	 * @author bhouston / http://clara.io
 10057  	 */
 10058  
 10059  	function Euler( x, y, z, order ) {
 10060  
 10061  		this._x = x || 0;
 10062  		this._y = y || 0;
 10063  		this._z = z || 0;
 10064  		this._order = order || Euler.DefaultOrder;
 10065  
 10066  	}
 10067  
 10068  	Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
 10069  
 10070  	Euler.DefaultOrder = 'XYZ';
 10071  
 10072  	Euler.prototype = {
 10073  
 10074  		constructor: Euler,
 10075  
 10076  		isEuler: true,
 10077  
 10078  		get x () {
 10079  
 10080  			return this._x;
 10081  
 10082  		},
 10083  
 10084  		set x ( value ) {
 10085  
 10086  			this._x = value;
 10087  			this.onChangeCallback();
 10088  
 10089  		},
 10090  
 10091  		get y () {
 10092  
 10093  			return this._y;
 10094  
 10095  		},
 10096  
 10097  		set y ( value ) {
 10098  
 10099  			this._y = value;
 10100  			this.onChangeCallback();
 10101  
 10102  		},
 10103  
 10104  		get z () {
 10105  
 10106  			return this._z;
 10107  
 10108  		},
 10109  
 10110  		set z ( value ) {
 10111  
 10112  			this._z = value;
 10113  			this.onChangeCallback();
 10114  
 10115  		},
 10116  
 10117  		get order () {
 10118  
 10119  			return this._order;
 10120  
 10121  		},
 10122  
 10123  		set order ( value ) {
 10124  
 10125  			this._order = value;
 10126  			this.onChangeCallback();
 10127  
 10128  		},
 10129  
 10130  		set: function ( x, y, z, order ) {
 10131  
 10132  			this._x = x;
 10133  			this._y = y;
 10134  			this._z = z;
 10135  			this._order = order || this._order;
 10136  
 10137  			this.onChangeCallback();
 10138  
 10139  			return this;
 10140  
 10141  		},
 10142  
 10143  		clone: function () {
 10144  
 10145  			return new this.constructor( this._x, this._y, this._z, this._order );
 10146  
 10147  		},
 10148  
 10149  		copy: function ( euler ) {
 10150  
 10151  			this._x = euler._x;
 10152  			this._y = euler._y;
 10153  			this._z = euler._z;
 10154  			this._order = euler._order;
 10155  
 10156  			this.onChangeCallback();
 10157  
 10158  			return this;
 10159  
 10160  		},
 10161  
 10162  		setFromRotationMatrix: function ( m, order, update ) {
 10163  
 10164  			var clamp = _Math.clamp;
 10165  
 10166  			// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
 10167  
 10168  			var te = m.elements;
 10169  			var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
 10170  			var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
 10171  			var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
 10172  
 10173  			order = order || this._order;
 10174  
 10175  			if ( order === 'XYZ' ) {
 10176  
 10177  				this._y = Math.asin( clamp( m13, - 1, 1 ) );
 10178  
 10179  				if ( Math.abs( m13 ) < 0.99999 ) {
 10180  
 10181  					this._x = Math.atan2( - m23, m33 );
 10182  					this._z = Math.atan2( - m12, m11 );
 10183  
 10184  				} else {
 10185  
 10186  					this._x = Math.atan2( m32, m22 );
 10187  					this._z = 0;
 10188  
 10189  				}
 10190  
 10191  			} else if ( order === 'YXZ' ) {
 10192  
 10193  				this._x = Math.asin( - clamp( m23, - 1, 1 ) );
 10194  
 10195  				if ( Math.abs( m23 ) < 0.99999 ) {
 10196  
 10197  					this._y = Math.atan2( m13, m33 );
 10198  					this._z = Math.atan2( m21, m22 );
 10199  
 10200  				} else {
 10201  
 10202  					this._y = Math.atan2( - m31, m11 );
 10203  					this._z = 0;
 10204  
 10205  				}
 10206  
 10207  			} else if ( order === 'ZXY' ) {
 10208  
 10209  				this._x = Math.asin( clamp( m32, - 1, 1 ) );
 10210  
 10211  				if ( Math.abs( m32 ) < 0.99999 ) {
 10212  
 10213  					this._y = Math.atan2( - m31, m33 );
 10214  					this._z = Math.atan2( - m12, m22 );
 10215  
 10216  				} else {
 10217  
 10218  					this._y = 0;
 10219  					this._z = Math.atan2( m21, m11 );
 10220  
 10221  				}
 10222  
 10223  			} else if ( order === 'ZYX' ) {
 10224  
 10225  				this._y = Math.asin( - clamp( m31, - 1, 1 ) );
 10226  
 10227  				if ( Math.abs( m31 ) < 0.99999 ) {
 10228  
 10229  					this._x = Math.atan2( m32, m33 );
 10230  					this._z = Math.atan2( m21, m11 );
 10231  
 10232  				} else {
 10233  
 10234  					this._x = 0;
 10235  					this._z = Math.atan2( - m12, m22 );
 10236  
 10237  				}
 10238  
 10239  			} else if ( order === 'YZX' ) {
 10240  
 10241  				this._z = Math.asin( clamp( m21, - 1, 1 ) );
 10242  
 10243  				if ( Math.abs( m21 ) < 0.99999 ) {
 10244  
 10245  					this._x = Math.atan2( - m23, m22 );
 10246  					this._y = Math.atan2( - m31, m11 );
 10247  
 10248  				} else {
 10249  
 10250  					this._x = 0;
 10251  					this._y = Math.atan2( m13, m33 );
 10252  
 10253  				}
 10254  
 10255  			} else if ( order === 'XZY' ) {
 10256  
 10257  				this._z = Math.asin( - clamp( m12, - 1, 1 ) );
 10258  
 10259  				if ( Math.abs( m12 ) < 0.99999 ) {
 10260  
 10261  					this._x = Math.atan2( m32, m22 );
 10262  					this._y = Math.atan2( m13, m11 );
 10263  
 10264  				} else {
 10265  
 10266  					this._x = Math.atan2( - m23, m33 );
 10267  					this._y = 0;
 10268  
 10269  				}
 10270  
 10271  			} else {
 10272  
 10273  				console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order );
 10274  
 10275  			}
 10276  
 10277  			this._order = order;
 10278  
 10279  			if ( update !== false ) this.onChangeCallback();
 10280  
 10281  			return this;
 10282  
 10283  		},
 10284  
 10285  		setFromQuaternion: function () {
 10286  
 10287  			var matrix;
 10288  
 10289  			return function setFromQuaternion( q, order, update ) {
 10290  
 10291  				if ( matrix === undefined ) matrix = new Matrix4();
 10292  
 10293  				matrix.makeRotationFromQuaternion( q );
 10294  
 10295  				return this.setFromRotationMatrix( matrix, order, update );
 10296  
 10297  			};
 10298  
 10299  		}(),
 10300  
 10301  		setFromVector3: function ( v, order ) {
 10302  
 10303  			return this.set( v.x, v.y, v.z, order || this._order );
 10304  
 10305  		},
 10306  
 10307  		reorder: function () {
 10308  
 10309  			// WARNING: this discards revolution information -bhouston
 10310  
 10311  			var q = new Quaternion();
 10312  
 10313  			return function reorder( newOrder ) {
 10314  
 10315  				q.setFromEuler( this );
 10316  
 10317  				return this.setFromQuaternion( q, newOrder );
 10318  
 10319  			};
 10320  
 10321  		}(),
 10322  
 10323  		equals: function ( euler ) {
 10324  
 10325  			return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
 10326  
 10327  		},
 10328  
 10329  		fromArray: function ( array ) {
 10330  
 10331  			this._x = array[ 0 ];
 10332  			this._y = array[ 1 ];
 10333  			this._z = array[ 2 ];
 10334  			if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
 10335  
 10336  			this.onChangeCallback();
 10337  
 10338  			return this;
 10339  
 10340  		},
 10341  
 10342  		toArray: function ( array, offset ) {
 10343  
 10344  			if ( array === undefined ) array = [];
 10345  			if ( offset === undefined ) offset = 0;
 10346  
 10347  			array[ offset ] = this._x;
 10348  			array[ offset + 1 ] = this._y;
 10349  			array[ offset + 2 ] = this._z;
 10350  			array[ offset + 3 ] = this._order;
 10351  
 10352  			return array;
 10353  
 10354  		},
 10355  
 10356  		toVector3: function ( optionalResult ) {
 10357  
 10358  			if ( optionalResult ) {
 10359  
 10360  				return optionalResult.set( this._x, this._y, this._z );
 10361  
 10362  			} else {
 10363  
 10364  				return new Vector3( this._x, this._y, this._z );
 10365  
 10366  			}
 10367  
 10368  		},
 10369  
 10370  		onChange: function ( callback ) {
 10371  
 10372  			this.onChangeCallback = callback;
 10373  
 10374  			return this;
 10375  
 10376  		},
 10377  
 10378  		onChangeCallback: function () {}
 10379  
 10380  	};
 10381  
 10382  	/**
 10383  	 * @author mrdoob / http://mrdoob.com/
 10384  	 */
 10385  
 10386  	function Layers() {
 10387  
 10388  		this.mask = 1;
 10389  
 10390  	}
 10391  
 10392  	Layers.prototype = {
 10393  
 10394  		constructor: Layers,
 10395  
 10396  		set: function ( channel ) {
 10397  
 10398  			this.mask = 1 << channel;
 10399  
 10400  		},
 10401  
 10402  		enable: function ( channel ) {
 10403  
 10404  			this.mask |= 1 << channel;
 10405  
 10406  		},
 10407  
 10408  		toggle: function ( channel ) {
 10409  
 10410  			this.mask ^= 1 << channel;
 10411  
 10412  		},
 10413  
 10414  		disable: function ( channel ) {
 10415  
 10416  			this.mask &= ~ ( 1 << channel );
 10417  
 10418  		},
 10419  
 10420  		test: function ( layers ) {
 10421  
 10422  			return ( this.mask & layers.mask ) !== 0;
 10423  
 10424  		}
 10425  
 10426  	};
 10427  
 10428  	/**
 10429  	 * @author mrdoob / http://mrdoob.com/
 10430  	 * @author mikael emtinger / http://gomo.se/
 10431  	 * @author alteredq / http://alteredqualia.com/
 10432  	 * @author WestLangley / http://github.com/WestLangley
 10433  	 * @author elephantatwork / www.elephantatwork.ch
 10434  	 */
 10435  
 10436  	var object3DId = 0;
 10437  
 10438  	function Object3D() {
 10439  
 10440  		Object.defineProperty( this, 'id', { value: object3DId ++ } );
 10441  
 10442  		this.uuid = _Math.generateUUID();
 10443  
 10444  		this.name = '';
 10445  		this.type = 'Object3D';
 10446  
 10447  		this.parent = null;
 10448  		this.children = [];
 10449  
 10450  		this.up = Object3D.DefaultUp.clone();
 10451  
 10452  		var position = new Vector3();
 10453  		var rotation = new Euler();
 10454  		var quaternion = new Quaternion();
 10455  		var scale = new Vector3( 1, 1, 1 );
 10456  
 10457  		function onRotationChange() {
 10458  
 10459  			quaternion.setFromEuler( rotation, false );
 10460  
 10461  		}
 10462  
 10463  		function onQuaternionChange() {
 10464  
 10465  			rotation.setFromQuaternion( quaternion, undefined, false );
 10466  
 10467  		}
 10468  
 10469  		rotation.onChange( onRotationChange );
 10470  		quaternion.onChange( onQuaternionChange );
 10471  
 10472  		Object.defineProperties( this, {
 10473  			position: {
 10474  				enumerable: true,
 10475  				value: position
 10476  			},
 10477  			rotation: {
 10478  				enumerable: true,
 10479  				value: rotation
 10480  			},
 10481  			quaternion: {
 10482  				enumerable: true,
 10483  				value: quaternion
 10484  			},
 10485  			scale: {
 10486  				enumerable: true,
 10487  				value: scale
 10488  			},
 10489  			modelViewMatrix: {
 10490  				value: new Matrix4()
 10491  			},
 10492  			normalMatrix: {
 10493  				value: new Matrix3()
 10494  			}
 10495  		} );
 10496  
 10497  		this.matrix = new Matrix4();
 10498  		this.matrixWorld = new Matrix4();
 10499  
 10500  		this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
 10501  		this.matrixWorldNeedsUpdate = false;
 10502  
 10503  		this.layers = new Layers();
 10504  		this.visible = true;
 10505  
 10506  		this.castShadow = false;
 10507  		this.receiveShadow = false;
 10508  
 10509  		this.frustumCulled = true;
 10510  		this.renderOrder = 0;
 10511  
 10512  		this.userData = {};
 10513  
 10514  		this.onBeforeRender = function () {};
 10515  		this.onAfterRender = function () {};
 10516  
 10517  	}
 10518  
 10519  	Object3D.DefaultUp = new Vector3( 0, 1, 0 );
 10520  	Object3D.DefaultMatrixAutoUpdate = true;
 10521  
 10522  	Object3D.prototype = {
 10523  
 10524  		constructor: Object3D,
 10525  
 10526  		isObject3D: true,
 10527  
 10528  		applyMatrix: function ( matrix ) {
 10529  
 10530  			this.matrix.multiplyMatrices( matrix, this.matrix );
 10531  
 10532  			this.matrix.decompose( this.position, this.quaternion, this.scale );
 10533  
 10534  		},
 10535  
 10536  		setRotationFromAxisAngle: function ( axis, angle ) {
 10537  
 10538  			// assumes axis is normalized
 10539  
 10540  			this.quaternion.setFromAxisAngle( axis, angle );
 10541  
 10542  		},
 10543  
 10544  		setRotationFromEuler: function ( euler ) {
 10545  
 10546  			this.quaternion.setFromEuler( euler, true );
 10547  
 10548  		},
 10549  
 10550  		setRotationFromMatrix: function ( m ) {
 10551  
 10552  			// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
 10553  
 10554  			this.quaternion.setFromRotationMatrix( m );
 10555  
 10556  		},
 10557  
 10558  		setRotationFromQuaternion: function ( q ) {
 10559  
 10560  			// assumes q is normalized
 10561  
 10562  			this.quaternion.copy( q );
 10563  
 10564  		},
 10565  
 10566  		rotateOnAxis: function () {
 10567  
 10568  			// rotate object on axis in object space
 10569  			// axis is assumed to be normalized
 10570  
 10571  			var q1 = new Quaternion();
 10572  
 10573  			return function rotateOnAxis( axis, angle ) {
 10574  
 10575  				q1.setFromAxisAngle( axis, angle );
 10576  
 10577  				this.quaternion.multiply( q1 );
 10578  
 10579  				return this;
 10580  
 10581  			};
 10582  
 10583  		}(),
 10584  
 10585  		rotateX: function () {
 10586  
 10587  			var v1 = new Vector3( 1, 0, 0 );
 10588  
 10589  			return function rotateX( angle ) {
 10590  
 10591  				return this.rotateOnAxis( v1, angle );
 10592  
 10593  			};
 10594  
 10595  		}(),
 10596  
 10597  		rotateY: function () {
 10598  
 10599  			var v1 = new Vector3( 0, 1, 0 );
 10600  
 10601  			return function rotateY( angle ) {
 10602  
 10603  				return this.rotateOnAxis( v1, angle );
 10604  
 10605  			};
 10606  
 10607  		}(),
 10608  
 10609  		rotateZ: function () {
 10610  
 10611  			var v1 = new Vector3( 0, 0, 1 );
 10612  
 10613  			return function rotateZ( angle ) {
 10614  
 10615  				return this.rotateOnAxis( v1, angle );
 10616  
 10617  			};
 10618  
 10619  		}(),
 10620  
 10621  		translateOnAxis: function () {
 10622  
 10623  			// translate object by distance along axis in object space
 10624  			// axis is assumed to be normalized
 10625  
 10626  			var v1 = new Vector3();
 10627  
 10628  			return function translateOnAxis( axis, distance ) {
 10629  
 10630  				v1.copy( axis ).applyQuaternion( this.quaternion );
 10631  
 10632  				this.position.add( v1.multiplyScalar( distance ) );
 10633  
 10634  				return this;
 10635  
 10636  			};
 10637  
 10638  		}(),
 10639  
 10640  		translateX: function () {
 10641  
 10642  			var v1 = new Vector3( 1, 0, 0 );
 10643  
 10644  			return function translateX( distance ) {
 10645  
 10646  				return this.translateOnAxis( v1, distance );
 10647  
 10648  			};
 10649  
 10650  		}(),
 10651  
 10652  		translateY: function () {
 10653  
 10654  			var v1 = new Vector3( 0, 1, 0 );
 10655  
 10656  			return function translateY( distance ) {
 10657  
 10658  				return this.translateOnAxis( v1, distance );
 10659  
 10660  			};
 10661  
 10662  		}(),
 10663  
 10664  		translateZ: function () {
 10665  
 10666  			var v1 = new Vector3( 0, 0, 1 );
 10667  
 10668  			return function translateZ( distance ) {
 10669  
 10670  				return this.translateOnAxis( v1, distance );
 10671  
 10672  			};
 10673  
 10674  		}(),
 10675  
 10676  		localToWorld: function ( vector ) {
 10677  
 10678  			return vector.applyMatrix4( this.matrixWorld );
 10679  
 10680  		},
 10681  
 10682  		worldToLocal: function () {
 10683  
 10684  			var m1 = new Matrix4();
 10685  
 10686  			return function worldToLocal( vector ) {
 10687  
 10688  				return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );
 10689  
 10690  			};
 10691  
 10692  		}(),
 10693  
 10694  		lookAt: function () {
 10695  
 10696  			// This routine does not support objects with rotated and/or translated parent(s)
 10697  
 10698  			var m1 = new Matrix4();
 10699  
 10700  			return function lookAt( vector ) {
 10701  
 10702  				m1.lookAt( vector, this.position, this.up );
 10703  
 10704  				this.quaternion.setFromRotationMatrix( m1 );
 10705  
 10706  			};
 10707  
 10708  		}(),
 10709  
 10710  		add: function ( object ) {
 10711  
 10712  			if ( arguments.length > 1 ) {
 10713  
 10714  				for ( var i = 0; i < arguments.length; i ++ ) {
 10715  
 10716  					this.add( arguments[ i ] );
 10717  
 10718  				}
 10719  
 10720  				return this;
 10721  
 10722  			}
 10723  
 10724  			if ( object === this ) {
 10725  
 10726  				console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object );
 10727  				return this;
 10728  
 10729  			}
 10730  
 10731  			if ( ( object && object.isObject3D ) ) {
 10732  
 10733  				if ( object.parent !== null ) {
 10734  
 10735  					object.parent.remove( object );
 10736  
 10737  				}
 10738  
 10739  				object.parent = this;
 10740  				object.dispatchEvent( { type: 'added' } );
 10741  
 10742  				this.children.push( object );
 10743  
 10744  			} else {
 10745  
 10746  				console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object );
 10747  
 10748  			}
 10749  
 10750  			return this;
 10751  
 10752  		},
 10753  
 10754  		remove: function ( object ) {
 10755  
 10756  			if ( arguments.length > 1 ) {
 10757  
 10758  				for ( var i = 0; i < arguments.length; i ++ ) {
 10759  
 10760  					this.remove( arguments[ i ] );
 10761  
 10762  				}
 10763  
 10764  			}
 10765  
 10766  			var index = this.children.indexOf( object );
 10767  
 10768  			if ( index !== - 1 ) {
 10769  
 10770  				object.parent = null;
 10771  
 10772  				object.dispatchEvent( { type: 'removed' } );
 10773  
 10774  				this.children.splice( index, 1 );
 10775  
 10776  			}
 10777  
 10778  		},
 10779  
 10780  		getObjectById: function ( id ) {
 10781  
 10782  			return this.getObjectByProperty( 'id', id );
 10783  
 10784  		},
 10785  
 10786  		getObjectByName: function ( name ) {
 10787  
 10788  			return this.getObjectByProperty( 'name', name );
 10789  
 10790  		},
 10791  
 10792  		getObjectByProperty: function ( name, value ) {
 10793  
 10794  			if ( this[ name ] === value ) return this;
 10795  
 10796  			for ( var i = 0, l = this.children.length; i < l; i ++ ) {
 10797  
 10798  				var child = this.children[ i ];
 10799  				var object = child.getObjectByProperty( name, value );
 10800  
 10801  				if ( object !== undefined ) {
 10802  
 10803  					return object;
 10804  
 10805  				}
 10806  
 10807  			}
 10808  
 10809  			return undefined;
 10810  
 10811  		},
 10812  
 10813  		getWorldPosition: function ( optionalTarget ) {
 10814  
 10815  			var result = optionalTarget || new Vector3();
 10816  
 10817  			this.updateMatrixWorld( true );
 10818  
 10819  			return result.setFromMatrixPosition( this.matrixWorld );
 10820  
 10821  		},
 10822  
 10823  		getWorldQuaternion: function () {
 10824  
 10825  			var position = new Vector3();
 10826  			var scale = new Vector3();
 10827  
 10828  			return function getWorldQuaternion( optionalTarget ) {
 10829  
 10830  				var result = optionalTarget || new Quaternion();
 10831  
 10832  				this.updateMatrixWorld( true );
 10833  
 10834  				this.matrixWorld.decompose( position, result, scale );
 10835  
 10836  				return result;
 10837  
 10838  			};
 10839  
 10840  		}(),
 10841  
 10842  		getWorldRotation: function () {
 10843  
 10844  			var quaternion = new Quaternion();
 10845  
 10846  			return function getWorldRotation( optionalTarget ) {
 10847  
 10848  				var result = optionalTarget || new Euler();
 10849  
 10850  				this.getWorldQuaternion( quaternion );
 10851  
 10852  				return result.setFromQuaternion( quaternion, this.rotation.order, false );
 10853  
 10854  			};
 10855  
 10856  		}(),
 10857  
 10858  		getWorldScale: function () {
 10859  
 10860  			var position = new Vector3();
 10861  			var quaternion = new Quaternion();
 10862  
 10863  			return function getWorldScale( optionalTarget ) {
 10864  
 10865  				var result = optionalTarget || new Vector3();
 10866  
 10867  				this.updateMatrixWorld( true );
 10868  
 10869  				this.matrixWorld.decompose( position, quaternion, result );
 10870  
 10871  				return result;
 10872  
 10873  			};
 10874  
 10875  		}(),
 10876  
 10877  		getWorldDirection: function () {
 10878  
 10879  			var quaternion = new Quaternion();
 10880  
 10881  			return function getWorldDirection( optionalTarget ) {
 10882  
 10883  				var result = optionalTarget || new Vector3();
 10884  
 10885  				this.getWorldQuaternion( quaternion );
 10886  
 10887  				return result.set( 0, 0, 1 ).applyQuaternion( quaternion );
 10888  
 10889  			};
 10890  
 10891  		}(),
 10892  
 10893  		raycast: function () {},
 10894  
 10895  		traverse: function ( callback ) {
 10896  
 10897  			callback( this );
 10898  
 10899  			var children = this.children;
 10900  
 10901  			for ( var i = 0, l = children.length; i < l; i ++ ) {
 10902  
 10903  				children[ i ].traverse( callback );
 10904  
 10905  			}
 10906  
 10907  		},
 10908  
 10909  		traverseVisible: function ( callback ) {
 10910  
 10911  			if ( this.visible === false ) return;
 10912  
 10913  			callback( this );
 10914  
 10915  			var children = this.children;
 10916  
 10917  			for ( var i = 0, l = children.length; i < l; i ++ ) {
 10918  
 10919  				children[ i ].traverseVisible( callback );
 10920  
 10921  			}
 10922  
 10923  		},
 10924  
 10925  		traverseAncestors: function ( callback ) {
 10926  
 10927  			var parent = this.parent;
 10928  
 10929  			if ( parent !== null ) {
 10930  
 10931  				callback( parent );
 10932  
 10933  				parent.traverseAncestors( callback );
 10934  
 10935  			}
 10936  
 10937  		},
 10938  
 10939  		updateMatrix: function () {
 10940  
 10941  			this.matrix.compose( this.position, this.quaternion, this.scale );
 10942  
 10943  			this.matrixWorldNeedsUpdate = true;
 10944  
 10945  		},
 10946  
 10947  		updateMatrixWorld: function ( force ) {
 10948  
 10949  			if ( this.matrixAutoUpdate === true ) this.updateMatrix();
 10950  
 10951  			if ( this.matrixWorldNeedsUpdate === true || force === true ) {
 10952  
 10953  				if ( this.parent === null ) {
 10954  
 10955  					this.matrixWorld.copy( this.matrix );
 10956  
 10957  				} else {
 10958  
 10959  					this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
 10960  
 10961  				}
 10962  
 10963  				this.matrixWorldNeedsUpdate = false;
 10964  
 10965  				force = true;
 10966  
 10967  			}
 10968  
 10969  			// update children
 10970  
 10971  			var children = this.children;
 10972  
 10973  			for ( var i = 0, l = children.length; i < l; i ++ ) {
 10974  
 10975  				children[ i ].updateMatrixWorld( force );
 10976  
 10977  			}
 10978  
 10979  		},
 10980  
 10981  		toJSON: function ( meta ) {
 10982  
 10983  			// meta is '' when called from JSON.stringify
 10984  			var isRootObject = ( meta === undefined || meta === '' );
 10985  
 10986  			var output = {};
 10987  
 10988  			// meta is a hash used to collect geometries, materials.
 10989  			// not providing it implies that this is the root object
 10990  			// being serialized.
 10991  			if ( isRootObject ) {
 10992  
 10993  				// initialize meta obj
 10994  				meta = {
 10995  					geometries: {},
 10996  					materials: {},
 10997  					textures: {},
 10998  					images: {}
 10999  				};
 11000  
 11001  				output.metadata = {
 11002  					version: 4.4,
 11003  					type: 'Object',
 11004  					generator: 'Object3D.toJSON'
 11005  				};
 11006  
 11007  			}
 11008  
 11009  			// standard Object3D serialization
 11010  
 11011  			var object = {};
 11012  
 11013  			object.uuid = this.uuid;
 11014  			object.type = this.type;
 11015  
 11016  			if ( this.name !== '' ) object.name = this.name;
 11017  			if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
 11018  			if ( this.castShadow === true ) object.castShadow = true;
 11019  			if ( this.receiveShadow === true ) object.receiveShadow = true;
 11020  			if ( this.visible === false ) object.visible = false;
 11021  
 11022  			object.matrix = this.matrix.toArray();
 11023  
 11024  			//
 11025  
 11026  			if ( this.geometry !== undefined ) {
 11027  
 11028  				if ( meta.geometries[ this.geometry.uuid ] === undefined ) {
 11029  
 11030  					meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON( meta );
 11031  
 11032  				}
 11033  
 11034  				object.geometry = this.geometry.uuid;
 11035  
 11036  			}
 11037  
 11038  			if ( this.material !== undefined ) {
 11039  
 11040  				if ( meta.materials[ this.material.uuid ] === undefined ) {
 11041  
 11042  					meta.materials[ this.material.uuid ] = this.material.toJSON( meta );
 11043  
 11044  				}
 11045  
 11046  				object.material = this.material.uuid;
 11047  
 11048  			}
 11049  
 11050  			//
 11051  
 11052  			if ( this.children.length > 0 ) {
 11053  
 11054  				object.children = [];
 11055  
 11056  				for ( var i = 0; i < this.children.length; i ++ ) {
 11057  
 11058  					object.children.push( this.children[ i ].toJSON( meta ).object );
 11059  
 11060  				}
 11061  
 11062  			}
 11063  
 11064  			if ( isRootObject ) {
 11065  
 11066  				var geometries = extractFromCache( meta.geometries );
 11067  				var materials = extractFromCache( meta.materials );
 11068  				var textures = extractFromCache( meta.textures );
 11069  				var images = extractFromCache( meta.images );
 11070  
 11071  				if ( geometries.length > 0 ) output.geometries = geometries;
 11072  				if ( materials.length > 0 ) output.materials = materials;
 11073  				if ( textures.length > 0 ) output.textures = textures;
 11074  				if ( images.length > 0 ) output.images = images;
 11075  
 11076  			}
 11077  
 11078  			output.object = object;
 11079  
 11080  			return output;
 11081  
 11082  			// extract data from the cache hash
 11083  			// remove metadata on each item
 11084  			// and return as array
 11085  			function extractFromCache( cache ) {
 11086  
 11087  				var values = [];
 11088  				for ( var key in cache ) {
 11089  
 11090  					var data = cache[ key ];
 11091  					delete data.metadata;
 11092  					values.push( data );
 11093  
 11094  				}
 11095  				return values;
 11096  
 11097  			}
 11098  
 11099  		},
 11100  
 11101  		clone: function ( recursive ) {
 11102  
 11103  			return new this.constructor().copy( this, recursive );
 11104  
 11105  		},
 11106  
 11107  		copy: function ( source, recursive ) {
 11108  
 11109  			if ( recursive === undefined ) recursive = true;
 11110  
 11111  			this.name = source.name;
 11112  
 11113  			this.up.copy( source.up );
 11114  
 11115  			this.position.copy( source.position );
 11116  			this.quaternion.copy( source.quaternion );
 11117  			this.scale.copy( source.scale );
 11118  
 11119  			this.matrix.copy( source.matrix );
 11120  			this.matrixWorld.copy( source.matrixWorld );
 11121  
 11122  			this.matrixAutoUpdate = source.matrixAutoUpdate;
 11123  			this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
 11124  
 11125  			this.layers.mask = source.layers.mask;
 11126  			this.visible = source.visible;
 11127  
 11128  			this.castShadow = source.castShadow;
 11129  			this.receiveShadow = source.receiveShadow;
 11130  
 11131  			this.frustumCulled = source.frustumCulled;
 11132  			this.renderOrder = source.renderOrder;
 11133  
 11134  			this.userData = JSON.parse( JSON.stringify( source.userData ) );
 11135  
 11136  			if ( recursive === true ) {
 11137  
 11138  				for ( var i = 0; i < source.children.length; i ++ ) {
 11139  
 11140  					var child = source.children[ i ];
 11141  					this.add( child.clone() );
 11142  
 11143  				}
 11144  
 11145  			}
 11146  
 11147  			return this;
 11148  
 11149  		}
 11150  
 11151  	};
 11152  
 11153  	Object.assign( Object3D.prototype, EventDispatcher.prototype );
 11154  
 11155  	/**
 11156  	 * @author bhouston / http://clara.io
 11157  	 */
 11158  
 11159  	function Line3( start, end ) {
 11160  
 11161  		this.start = ( start !== undefined ) ? start : new Vector3();
 11162  		this.end = ( end !== undefined ) ? end : new Vector3();
 11163  
 11164  	}
 11165  
 11166  	Line3.prototype = {
 11167  
 11168  		constructor: Line3,
 11169  
 11170  		set: function ( start, end ) {
 11171  
 11172  			this.start.copy( start );
 11173  			this.end.copy( end );
 11174  
 11175  			return this;
 11176  
 11177  		},
 11178  
 11179  		clone: function () {
 11180  
 11181  			return new this.constructor().copy( this );
 11182  
 11183  		},
 11184  
 11185  		copy: function ( line ) {
 11186  
 11187  			this.start.copy( line.start );
 11188  			this.end.copy( line.end );
 11189  
 11190  			return this;
 11191  
 11192  		},
 11193  
 11194  		getCenter: function ( optionalTarget ) {
 11195  
 11196  			var result = optionalTarget || new Vector3();
 11197  			return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
 11198  
 11199  		},
 11200  
 11201  		delta: function ( optionalTarget ) {
 11202  
 11203  			var result = optionalTarget || new Vector3();
 11204  			return result.subVectors( this.end, this.start );
 11205  
 11206  		},
 11207  
 11208  		distanceSq: function () {
 11209  
 11210  			return this.start.distanceToSquared( this.end );
 11211  
 11212  		},
 11213  
 11214  		distance: function () {
 11215  
 11216  			return this.start.distanceTo( this.end );
 11217  
 11218  		},
 11219  
 11220  		at: function ( t, optionalTarget ) {
 11221  
 11222  			var result = optionalTarget || new Vector3();
 11223  
 11224  			return this.delta( result ).multiplyScalar( t ).add( this.start );
 11225  
 11226  		},
 11227  
 11228  		closestPointToPointParameter: function () {
 11229  
 11230  			var startP = new Vector3();
 11231  			var startEnd = new Vector3();
 11232  
 11233  			return function closestPointToPointParameter( point, clampToLine ) {
 11234  
 11235  				startP.subVectors( point, this.start );
 11236  				startEnd.subVectors( this.end, this.start );
 11237  
 11238  				var startEnd2 = startEnd.dot( startEnd );
 11239  				var startEnd_startP = startEnd.dot( startP );
 11240  
 11241  				var t = startEnd_startP / startEnd2;
 11242  
 11243  				if ( clampToLine ) {
 11244  
 11245  					t = _Math.clamp( t, 0, 1 );
 11246  
 11247  				}
 11248  
 11249  				return t;
 11250  
 11251  			};
 11252  
 11253  		}(),
 11254  
 11255  		closestPointToPoint: function ( point, clampToLine, optionalTarget ) {
 11256  
 11257  			var t = this.closestPointToPointParameter( point, clampToLine );
 11258  
 11259  			var result = optionalTarget || new Vector3();
 11260  
 11261  			return this.delta( result ).multiplyScalar( t ).add( this.start );
 11262  
 11263  		},
 11264  
 11265  		applyMatrix4: function ( matrix ) {
 11266  
 11267  			this.start.applyMatrix4( matrix );
 11268  			this.end.applyMatrix4( matrix );
 11269  
 11270  			return this;
 11271  
 11272  		},
 11273  
 11274  		equals: function ( line ) {
 11275  
 11276  			return line.start.equals( this.start ) && line.end.equals( this.end );
 11277  
 11278  		}
 11279  
 11280  	};
 11281  
 11282  	/**
 11283  	 * @author bhouston / http://clara.io
 11284  	 * @author mrdoob / http://mrdoob.com/
 11285  	 */
 11286  
 11287  	function Triangle( a, b, c ) {
 11288  
 11289  		this.a = ( a !== undefined ) ? a : new Vector3();
 11290  		this.b = ( b !== undefined ) ? b : new Vector3();
 11291  		this.c = ( c !== undefined ) ? c : new Vector3();
 11292  
 11293  	}
 11294  
 11295  	Triangle.normal = function () {
 11296  
 11297  		var v0 = new Vector3();
 11298  
 11299  		return function normal( a, b, c, optionalTarget ) {
 11300  
 11301  			var result = optionalTarget || new Vector3();
 11302  
 11303  			result.subVectors( c, b );
 11304  			v0.subVectors( a, b );
 11305  			result.cross( v0 );
 11306  
 11307  			var resultLengthSq = result.lengthSq();
 11308  			if ( resultLengthSq > 0 ) {
 11309  
 11310  				return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );
 11311  
 11312  			}
 11313  
 11314  			return result.set( 0, 0, 0 );
 11315  
 11316  		};
 11317  
 11318  	}();
 11319  
 11320  	// static/instance method to calculate barycentric coordinates
 11321  	// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
 11322  	Triangle.barycoordFromPoint = function () {
 11323  
 11324  		var v0 = new Vector3();
 11325  		var v1 = new Vector3();
 11326  		var v2 = new Vector3();
 11327  
 11328  		return function barycoordFromPoint( point, a, b, c, optionalTarget ) {
 11329  
 11330  			v0.subVectors( c, a );
 11331  			v1.subVectors( b, a );
 11332  			v2.subVectors( point, a );
 11333  
 11334  			var dot00 = v0.dot( v0 );
 11335  			var dot01 = v0.dot( v1 );
 11336  			var dot02 = v0.dot( v2 );
 11337  			var dot11 = v1.dot( v1 );
 11338  			var dot12 = v1.dot( v2 );
 11339  
 11340  			var denom = ( dot00 * dot11 - dot01 * dot01 );
 11341  
 11342  			var result = optionalTarget || new Vector3();
 11343  
 11344  			// collinear or singular triangle
 11345  			if ( denom === 0 ) {
 11346  
 11347  				// arbitrary location outside of triangle?
 11348  				// not sure if this is the best idea, maybe should be returning undefined
 11349  				return result.set( - 2, - 1, - 1 );
 11350  
 11351  			}
 11352  
 11353  			var invDenom = 1 / denom;
 11354  			var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
 11355  			var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
 11356  
 11357  			// barycentric coordinates must always sum to 1
 11358  			return result.set( 1 - u - v, v, u );
 11359  
 11360  		};
 11361  
 11362  	}();
 11363  
 11364  	Triangle.containsPoint = function () {
 11365  
 11366  		var v1 = new Vector3();
 11367  
 11368  		return function containsPoint( point, a, b, c ) {
 11369  
 11370  			var result = Triangle.barycoordFromPoint( point, a, b, c, v1 );
 11371  
 11372  			return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );
 11373  
 11374  		};
 11375  
 11376  	}();
 11377  
 11378  	Triangle.prototype = {
 11379  
 11380  		constructor: Triangle,
 11381  
 11382  		set: function ( a, b, c ) {
 11383  
 11384  			this.a.copy( a );
 11385  			this.b.copy( b );
 11386  			this.c.copy( c );
 11387  
 11388  			return this;
 11389  
 11390  		},
 11391  
 11392  		setFromPointsAndIndices: function ( points, i0, i1, i2 ) {
 11393  
 11394  			this.a.copy( points[ i0 ] );
 11395  			this.b.copy( points[ i1 ] );
 11396  			this.c.copy( points[ i2 ] );
 11397  
 11398  			return this;
 11399  
 11400  		},
 11401  
 11402  		clone: function () {
 11403  
 11404  			return new this.constructor().copy( this );
 11405  
 11406  		},
 11407  
 11408  		copy: function ( triangle ) {
 11409  
 11410  			this.a.copy( triangle.a );
 11411  			this.b.copy( triangle.b );
 11412  			this.c.copy( triangle.c );
 11413  
 11414  			return this;
 11415  
 11416  		},
 11417  
 11418  		area: function () {
 11419  
 11420  			var v0 = new Vector3();
 11421  			var v1 = new Vector3();
 11422  
 11423  			return function area() {
 11424  
 11425  				v0.subVectors( this.c, this.b );
 11426  				v1.subVectors( this.a, this.b );
 11427  
 11428  				return v0.cross( v1 ).length() * 0.5;
 11429  
 11430  			};
 11431  
 11432  		}(),
 11433  
 11434  		midpoint: function ( optionalTarget ) {
 11435  
 11436  			var result = optionalTarget || new Vector3();
 11437  			return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
 11438  
 11439  		},
 11440  
 11441  		normal: function ( optionalTarget ) {
 11442  
 11443  			return Triangle.normal( this.a, this.b, this.c, optionalTarget );
 11444  
 11445  		},
 11446  
 11447  		plane: function ( optionalTarget ) {
 11448  
 11449  			var result = optionalTarget || new Plane();
 11450  
 11451  			return result.setFromCoplanarPoints( this.a, this.b, this.c );
 11452  
 11453  		},
 11454  
 11455  		barycoordFromPoint: function ( point, optionalTarget ) {
 11456  
 11457  			return Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget );
 11458  
 11459  		},
 11460  
 11461  		containsPoint: function ( point ) {
 11462  
 11463  			return Triangle.containsPoint( point, this.a, this.b, this.c );
 11464  
 11465  		},
 11466  
 11467  		closestPointToPoint: function () {
 11468  
 11469  			var plane, edgeList, projectedPoint, closestPoint;
 11470  
 11471  			return function closestPointToPoint( point, optionalTarget ) {
 11472  
 11473  				if ( plane === undefined ) {
 11474  
 11475  					plane = new Plane();
 11476  					edgeList = [ new Line3(), new Line3(), new Line3() ];
 11477  					projectedPoint = new Vector3();
 11478  					closestPoint = new Vector3();
 11479  
 11480  				}
 11481  
 11482  				var result = optionalTarget || new Vector3();
 11483  				var minDistance = Infinity;
 11484  
 11485  				// project the point onto the plane of the triangle
 11486  
 11487  				plane.setFromCoplanarPoints( this.a, this.b, this.c );
 11488  				plane.projectPoint( point, projectedPoint );
 11489  
 11490  				// check if the projection lies within the triangle
 11491  
 11492  				if( this.containsPoint( projectedPoint ) === true ) {
 11493  
 11494  					// if so, this is the closest point
 11495  
 11496  					result.copy( projectedPoint );
 11497  
 11498  				} else {
 11499  
 11500  					// if not, the point falls outside the triangle. the result is the closest point to the triangle's edges or vertices
 11501  
 11502  					edgeList[ 0 ].set( this.a, this.b );
 11503  					edgeList[ 1 ].set( this.b, this.c );
 11504  					edgeList[ 2 ].set( this.c, this.a );
 11505  
 11506  					for( var i = 0; i < edgeList.length; i ++ ) {
 11507  
 11508  						edgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint );
 11509  
 11510  						var distance = projectedPoint.distanceToSquared( closestPoint );
 11511  
 11512  						if( distance < minDistance ) {
 11513  
 11514  							minDistance = distance;
 11515  
 11516  							result.copy( closestPoint );
 11517  
 11518  						}
 11519  
 11520  					}
 11521  
 11522  				}
 11523  
 11524  				return result;
 11525  
 11526  			};
 11527  
 11528  		}(),
 11529  
 11530  		equals: function ( triangle ) {
 11531  
 11532  			return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
 11533  
 11534  		}
 11535  
 11536  	};
 11537  
 11538  	/**
 11539  	 * @author mrdoob / http://mrdoob.com/
 11540  	 * @author alteredq / http://alteredqualia.com/
 11541  	 */
 11542  
 11543  	function Face3( a, b, c, normal, color, materialIndex ) {
 11544  
 11545  		this.a = a;
 11546  		this.b = b;
 11547  		this.c = c;
 11548  
 11549  		this.normal = (normal && normal.isVector3) ? normal : new Vector3();
 11550  		this.vertexNormals = Array.isArray( normal ) ? normal : [];
 11551  
 11552  		this.color = (color && color.isColor) ? color : new Color();
 11553  		this.vertexColors = Array.isArray( color ) ? color : [];
 11554  
 11555  		this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
 11556  
 11557  	}
 11558  
 11559  	Face3.prototype = {
 11560  
 11561  		constructor: Face3,
 11562  
 11563  		clone: function () {
 11564  
 11565  			return new this.constructor().copy( this );
 11566  
 11567  		},
 11568  
 11569  		copy: function ( source ) {
 11570  
 11571  			this.a = source.a;
 11572  			this.b = source.b;
 11573  			this.c = source.c;
 11574  
 11575  			this.normal.copy( source.normal );
 11576  			this.color.copy( source.color );
 11577  
 11578  			this.materialIndex = source.materialIndex;
 11579  
 11580  			for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) {
 11581  
 11582  				this.vertexNormals[ i ] = source.vertexNormals[ i ].clone();
 11583  
 11584  			}
 11585  
 11586  			for ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) {
 11587  
 11588  				this.vertexColors[ i ] = source.vertexColors[ i ].clone();
 11589  
 11590  			}
 11591  
 11592  			return this;
 11593  
 11594  		}
 11595  
 11596  	};
 11597  
 11598  	/**
 11599  	 * @author mrdoob / http://mrdoob.com/
 11600  	 * @author alteredq / http://alteredqualia.com/
 11601  	 *
 11602  	 * parameters = {
 11603  	 *  color: <hex>,
 11604  	 *  opacity: <float>,
 11605  	 *  map: new THREE.Texture( <Image> ),
 11606  	 *
 11607  	 *  lightMap: new THREE.Texture( <Image> ),
 11608  	 *  lightMapIntensity: <float>
 11609  	 *
 11610  	 *  aoMap: new THREE.Texture( <Image> ),
 11611  	 *  aoMapIntensity: <float>
 11612  	 *
 11613  	 *  specularMap: new THREE.Texture( <Image> ),
 11614  	 *
 11615  	 *  alphaMap: new THREE.Texture( <Image> ),
 11616  	 *
 11617  	 *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
 11618  	 *  combine: THREE.Multiply,
 11619  	 *  reflectivity: <float>,
 11620  	 *  refractionRatio: <float>,
 11621  	 *
 11622  	 *  shading: THREE.SmoothShading,
 11623  	 *  depthTest: <bool>,
 11624  	 *  depthWrite: <bool>,
 11625  	 *
 11626  	 *  wireframe: <boolean>,
 11627  	 *  wireframeLinewidth: <float>,
 11628  	 *
 11629  	 *  skinning: <bool>,
 11630  	 *  morphTargets: <bool>
 11631  	 * }
 11632  	 */
 11633  
 11634  	function MeshBasicMaterial( parameters ) {
 11635  
 11636  		Material.call( this );
 11637  
 11638  		this.type = 'MeshBasicMaterial';
 11639  
 11640  		this.color = new Color( 0xffffff ); // emissive
 11641  
 11642  		this.map = null;
 11643  
 11644  		this.lightMap = null;
 11645  		this.lightMapIntensity = 1.0;
 11646  
 11647  		this.aoMap = null;
 11648  		this.aoMapIntensity = 1.0;
 11649  
 11650  		this.specularMap = null;
 11651  
 11652  		this.alphaMap = null;
 11653  
 11654  		this.envMap = null;
 11655  		this.combine = MultiplyOperation;
 11656  		this.reflectivity = 1;
 11657  		this.refractionRatio = 0.98;
 11658  
 11659  		this.wireframe = false;
 11660  		this.wireframeLinewidth = 1;
 11661  		this.wireframeLinecap = 'round';
 11662  		this.wireframeLinejoin = 'round';
 11663  
 11664  		this.skinning = false;
 11665  		this.morphTargets = false;
 11666  
 11667  		this.lights = false;
 11668  
 11669  		this.setValues( parameters );
 11670  
 11671  	}
 11672  
 11673  	MeshBasicMaterial.prototype = Object.create( Material.prototype );
 11674  	MeshBasicMaterial.prototype.constructor = MeshBasicMaterial;
 11675  
 11676  	MeshBasicMaterial.prototype.isMeshBasicMaterial = true;
 11677  
 11678  	MeshBasicMaterial.prototype.copy = function ( source ) {
 11679  
 11680  		Material.prototype.copy.call( this, source );
 11681  
 11682  		this.color.copy( source.color );
 11683  
 11684  		this.map = source.map;
 11685  
 11686  		this.lightMap = source.lightMap;
 11687  		this.lightMapIntensity = source.lightMapIntensity;
 11688  
 11689  		this.aoMap = source.aoMap;
 11690  		this.aoMapIntensity = source.aoMapIntensity;
 11691  
 11692  		this.specularMap = source.specularMap;
 11693  
 11694  		this.alphaMap = source.alphaMap;
 11695  
 11696  		this.envMap = source.envMap;
 11697  		this.combine = source.combine;
 11698  		this.reflectivity = source.reflectivity;
 11699  		this.refractionRatio = source.refractionRatio;
 11700  
 11701  		this.wireframe = source.wireframe;
 11702  		this.wireframeLinewidth = source.wireframeLinewidth;
 11703  		this.wireframeLinecap = source.wireframeLinecap;
 11704  		this.wireframeLinejoin = source.wireframeLinejoin;
 11705  
 11706  		this.skinning = source.skinning;
 11707  		this.morphTargets = source.morphTargets;
 11708  
 11709  		return this;
 11710  
 11711  	};
 11712  
 11713  	/**
 11714  	 * @author mrdoob / http://mrdoob.com/
 11715  	 */
 11716  
 11717  	function BufferAttribute( array, itemSize, normalized ) {
 11718  
 11719  		if ( Array.isArray( array ) ) {
 11720  
 11721  			throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
 11722  
 11723  		}
 11724  
 11725  		this.uuid = _Math.generateUUID();
 11726  
 11727  		this.array = array;
 11728  		this.itemSize = itemSize;
 11729  		this.count = array !== undefined ? array.length / itemSize : 0;
 11730  		this.normalized = normalized === true;
 11731  
 11732  		this.dynamic = false;
 11733  		this.updateRange = { offset: 0, count: - 1 };
 11734  
 11735  		this.onUploadCallback = function () {};
 11736  
 11737  		this.version = 0;
 11738  
 11739  	}
 11740  
 11741  	BufferAttribute.prototype = {
 11742  
 11743  		constructor: BufferAttribute,
 11744  
 11745  		isBufferAttribute: true,
 11746  
 11747  		set needsUpdate( value ) {
 11748  
 11749  			if ( value === true ) this.version ++;
 11750  
 11751  		},
 11752  
 11753  		setArray: function ( array ) {
 11754  
 11755  			if ( Array.isArray( array ) ) {
 11756  
 11757  				throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
 11758  
 11759  			}
 11760  
 11761  			this.count = array !== undefined ? array.length / this.itemSize : 0;
 11762  			this.array = array;
 11763  
 11764  		},
 11765  
 11766  		setDynamic: function ( value ) {
 11767  
 11768  			this.dynamic = value;
 11769  
 11770  			return this;
 11771  
 11772  		},
 11773  
 11774  		copy: function ( source ) {
 11775  
 11776  			this.array = new source.array.constructor( source.array );
 11777  			this.itemSize = source.itemSize;
 11778  			this.count = source.count;
 11779  			this.normalized = source.normalized;
 11780  
 11781  			this.dynamic = source.dynamic;
 11782  
 11783  			return this;
 11784  
 11785  		},
 11786  
 11787  		copyAt: function ( index1, attribute, index2 ) {
 11788  
 11789  			index1 *= this.itemSize;
 11790  			index2 *= attribute.itemSize;
 11791  
 11792  			for ( var i = 0, l = this.itemSize; i < l; i ++ ) {
 11793  
 11794  				this.array[ index1 + i ] = attribute.array[ index2 + i ];
 11795  
 11796  			}
 11797  
 11798  			return this;
 11799  
 11800  		},
 11801  
 11802  		copyArray: function ( array ) {
 11803  
 11804  			this.array.set( array );
 11805  
 11806  			return this;
 11807  
 11808  		},
 11809  
 11810  		copyColorsArray: function ( colors ) {
 11811  
 11812  			var array = this.array, offset = 0;
 11813  
 11814  			for ( var i = 0, l = colors.length; i < l; i ++ ) {
 11815  
 11816  				var color = colors[ i ];
 11817  
 11818  				if ( color === undefined ) {
 11819  
 11820  					console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i );
 11821  					color = new Color();
 11822  
 11823  				}
 11824  
 11825  				array[ offset ++ ] = color.r;
 11826  				array[ offset ++ ] = color.g;
 11827  				array[ offset ++ ] = color.b;
 11828  
 11829  			}
 11830  
 11831  			return this;
 11832  
 11833  		},
 11834  
 11835  		copyIndicesArray: function ( indices ) {
 11836  
 11837  			var array = this.array, offset = 0;
 11838  
 11839  			for ( var i = 0, l = indices.length; i < l; i ++ ) {
 11840  
 11841  				var index = indices[ i ];
 11842  
 11843  				array[ offset ++ ] = index.a;
 11844  				array[ offset ++ ] = index.b;
 11845  				array[ offset ++ ] = index.c;
 11846  
 11847  			}
 11848  
 11849  			return this;
 11850  
 11851  		},
 11852  
 11853  		copyVector2sArray: function ( vectors ) {
 11854  
 11855  			var array = this.array, offset = 0;
 11856  
 11857  			for ( var i = 0, l = vectors.length; i < l; i ++ ) {
 11858  
 11859  				var vector = vectors[ i ];
 11860  
 11861  				if ( vector === undefined ) {
 11862  
 11863  					console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i );
 11864  					vector = new Vector2();
 11865  
 11866  				}
 11867  
 11868  				array[ offset ++ ] = vector.x;
 11869  				array[ offset ++ ] = vector.y;
 11870  
 11871  			}
 11872  
 11873  			return this;
 11874  
 11875  		},
 11876  
 11877  		copyVector3sArray: function ( vectors ) {
 11878  
 11879  			var array = this.array, offset = 0;
 11880  
 11881  			for ( var i = 0, l = vectors.length; i < l; i ++ ) {
 11882  
 11883  				var vector = vectors[ i ];
 11884  
 11885  				if ( vector === undefined ) {
 11886  
 11887  					console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i );
 11888  					vector = new Vector3();
 11889  
 11890  				}
 11891  
 11892  				array[ offset ++ ] = vector.x;
 11893  				array[ offset ++ ] = vector.y;
 11894  				array[ offset ++ ] = vector.z;
 11895  
 11896  			}
 11897  
 11898  			return this;
 11899  
 11900  		},
 11901  
 11902  		copyVector4sArray: function ( vectors ) {
 11903  
 11904  			var array = this.array, offset = 0;
 11905  
 11906  			for ( var i = 0, l = vectors.length; i < l; i ++ ) {
 11907  
 11908  				var vector = vectors[ i ];
 11909  
 11910  				if ( vector === undefined ) {
 11911  
 11912  					console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );
 11913  					vector = new Vector4();
 11914  
 11915  				}
 11916  
 11917  				array[ offset ++ ] = vector.x;
 11918  				array[ offset ++ ] = vector.y;
 11919  				array[ offset ++ ] = vector.z;
 11920  				array[ offset ++ ] = vector.w;
 11921  
 11922  			}
 11923  
 11924  			return this;
 11925  
 11926  		},
 11927  
 11928  		set: function ( value, offset ) {
 11929  
 11930  			if ( offset === undefined ) offset = 0;
 11931  
 11932  			this.array.set( value, offset );
 11933  
 11934  			return this;
 11935  
 11936  		},
 11937  
 11938  		getX: function ( index ) {
 11939  
 11940  			return this.array[ index * this.itemSize ];
 11941  
 11942  		},
 11943  
 11944  		setX: function ( index, x ) {
 11945  
 11946  			this.array[ index * this.itemSize ] = x;
 11947  
 11948  			return this;
 11949  
 11950  		},
 11951  
 11952  		getY: function ( index ) {
 11953  
 11954  			return this.array[ index * this.itemSize + 1 ];
 11955  
 11956  		},
 11957  
 11958  		setY: function ( index, y ) {
 11959  
 11960  			this.array[ index * this.itemSize + 1 ] = y;
 11961  
 11962  			return this;
 11963  
 11964  		},
 11965  
 11966  		getZ: function ( index ) {
 11967  
 11968  			return this.array[ index * this.itemSize + 2 ];
 11969  
 11970  		},
 11971  
 11972  		setZ: function ( index, z ) {
 11973  
 11974  			this.array[ index * this.itemSize + 2 ] = z;
 11975  
 11976  			return this;
 11977  
 11978  		},
 11979  
 11980  		getW: function ( index ) {
 11981  
 11982  			return this.array[ index * this.itemSize + 3 ];
 11983  
 11984  		},
 11985  
 11986  		setW: function ( index, w ) {
 11987  
 11988  			this.array[ index * this.itemSize + 3 ] = w;
 11989  
 11990  			return this;
 11991  
 11992  		},
 11993  
 11994  		setXY: function ( index, x, y ) {
 11995  
 11996  			index *= this.itemSize;
 11997  
 11998  			this.array[ index + 0 ] = x;
 11999  			this.array[ index + 1 ] = y;
 12000  
 12001  			return this;
 12002  
 12003  		},
 12004  
 12005  		setXYZ: function ( index, x, y, z ) {
 12006  
 12007  			index *= this.itemSize;
 12008  
 12009  			this.array[ index + 0 ] = x;
 12010  			this.array[ index + 1 ] = y;
 12011  			this.array[ index + 2 ] = z;
 12012  
 12013  			return this;
 12014  
 12015  		},
 12016  
 12017  		setXYZW: function ( index, x, y, z, w ) {
 12018  
 12019  			index *= this.itemSize;
 12020  
 12021  			this.array[ index + 0 ] = x;
 12022  			this.array[ index + 1 ] = y;
 12023  			this.array[ index + 2 ] = z;
 12024  			this.array[ index + 3 ] = w;
 12025  
 12026  			return this;
 12027  
 12028  		},
 12029  
 12030  		onUpload: function ( callback ) {
 12031  
 12032  			this.onUploadCallback = callback;
 12033  
 12034  			return this;
 12035  
 12036  		},
 12037  
 12038  		clone: function () {
 12039  
 12040  			return new this.constructor( this.array, this.itemSize ).copy( this );
 12041  
 12042  		}
 12043  
 12044  	};
 12045  
 12046  	//
 12047  
 12048  	function Int8BufferAttribute( array, itemSize ) {
 12049  
 12050  		BufferAttribute.call( this, new Int8Array( array ), itemSize );
 12051  
 12052  	}
 12053  
 12054  	Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
 12055  	Int8BufferAttribute.prototype.constructor = Int8BufferAttribute;
 12056  
 12057  
 12058  	function Uint8BufferAttribute( array, itemSize ) {
 12059  
 12060  		BufferAttribute.call( this, new Uint8Array( array ), itemSize );
 12061  
 12062  	}
 12063  
 12064  	Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
 12065  	Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute;
 12066  
 12067  
 12068  	function Uint8ClampedBufferAttribute( array, itemSize ) {
 12069  
 12070  		BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize );
 12071  
 12072  	}
 12073  
 12074  	Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );
 12075  	Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute;
 12076  
 12077  
 12078  	function Int16BufferAttribute( array, itemSize ) {
 12079  
 12080  		BufferAttribute.call( this, new Int16Array( array ), itemSize );
 12081  
 12082  	}
 12083  
 12084  	Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
 12085  	Int16BufferAttribute.prototype.constructor = Int16BufferAttribute;
 12086  
 12087  
 12088  	function Uint16BufferAttribute( array, itemSize ) {
 12089  
 12090  		BufferAttribute.call( this, new Uint16Array( array ), itemSize );
 12091  
 12092  	}
 12093  
 12094  	Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
 12095  	Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute;
 12096  
 12097  
 12098  	function Int32BufferAttribute( array, itemSize ) {
 12099  
 12100  		BufferAttribute.call( this, new Int32Array( array ), itemSize );
 12101  
 12102  	}
 12103  
 12104  	Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
 12105  	Int32BufferAttribute.prototype.constructor = Int32BufferAttribute;
 12106  
 12107  
 12108  	function Uint32BufferAttribute( array, itemSize ) {
 12109  
 12110  		BufferAttribute.call( this, new Uint32Array( array ), itemSize );
 12111  
 12112  	}
 12113  
 12114  	Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
 12115  	Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute;
 12116  
 12117  
 12118  	function Float32BufferAttribute( array, itemSize ) {
 12119  
 12120  		BufferAttribute.call( this, new Float32Array( array ), itemSize );
 12121  
 12122  	}
 12123  
 12124  	Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
 12125  	Float32BufferAttribute.prototype.constructor = Float32BufferAttribute;
 12126  
 12127  
 12128  	function Float64BufferAttribute( array, itemSize ) {
 12129  
 12130  		BufferAttribute.call( this, new Float64Array( array ), itemSize );
 12131  
 12132  	}
 12133  
 12134  	Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
 12135  	Float64BufferAttribute.prototype.constructor = Float64BufferAttribute;
 12136  
 12137  	/**
 12138  	 * @author mrdoob / http://mrdoob.com/
 12139  	 */
 12140  
 12141  	function DirectGeometry() {
 12142  
 12143  		this.indices = [];
 12144  		this.vertices = [];
 12145  		this.normals = [];
 12146  		this.colors = [];
 12147  		this.uvs = [];
 12148  		this.uvs2 = [];
 12149  
 12150  		this.groups = [];
 12151  
 12152  		this.morphTargets = {};
 12153  
 12154  		this.skinWeights = [];
 12155  		this.skinIndices = [];
 12156  
 12157  		// this.lineDistances = [];
 12158  
 12159  		this.boundingBox = null;
 12160  		this.boundingSphere = null;
 12161  
 12162  		// update flags
 12163  
 12164  		this.verticesNeedUpdate = false;
 12165  		this.normalsNeedUpdate = false;
 12166  		this.colorsNeedUpdate = false;
 12167  		this.uvsNeedUpdate = false;
 12168  		this.groupsNeedUpdate = false;
 12169  
 12170  	}
 12171  
 12172  	Object.assign( DirectGeometry.prototype, {
 12173  
 12174  		computeGroups: function ( geometry ) {
 12175  
 12176  			var group;
 12177  			var groups = [];
 12178  			var materialIndex = undefined;
 12179  
 12180  			var faces = geometry.faces;
 12181  
 12182  			for ( var i = 0; i < faces.length; i ++ ) {
 12183  
 12184  				var face = faces[ i ];
 12185  
 12186  				// materials
 12187  
 12188  				if ( face.materialIndex !== materialIndex ) {
 12189  
 12190  					materialIndex = face.materialIndex;
 12191  
 12192  					if ( group !== undefined ) {
 12193  
 12194  						group.count = ( i * 3 ) - group.start;
 12195  						groups.push( group );
 12196  
 12197  					}
 12198  
 12199  					group = {
 12200  						start: i * 3,
 12201  						materialIndex: materialIndex
 12202  					};
 12203  
 12204  				}
 12205  
 12206  			}
 12207  
 12208  			if ( group !== undefined ) {
 12209  
 12210  				group.count = ( i * 3 ) - group.start;
 12211  				groups.push( group );
 12212  
 12213  			}
 12214  
 12215  			this.groups = groups;
 12216  
 12217  		},
 12218  
 12219  		fromGeometry: function ( geometry ) {
 12220  
 12221  			var faces = geometry.faces;
 12222  			var vertices = geometry.vertices;
 12223  			var faceVertexUvs = geometry.faceVertexUvs;
 12224  
 12225  			var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
 12226  			var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
 12227  
 12228  			// morphs
 12229  
 12230  			var morphTargets = geometry.morphTargets;
 12231  			var morphTargetsLength = morphTargets.length;
 12232  
 12233  			var morphTargetsPosition;
 12234  
 12235  			if ( morphTargetsLength > 0 ) {
 12236  
 12237  				morphTargetsPosition = [];
 12238  
 12239  				for ( var i = 0; i < morphTargetsLength; i ++ ) {
 12240  
 12241  					morphTargetsPosition[ i ] = [];
 12242  
 12243  				}
 12244  
 12245  				this.morphTargets.position = morphTargetsPosition;
 12246  
 12247  			}
 12248  
 12249  			var morphNormals = geometry.morphNormals;
 12250  			var morphNormalsLength = morphNormals.length;
 12251  
 12252  			var morphTargetsNormal;
 12253  
 12254  			if ( morphNormalsLength > 0 ) {
 12255  
 12256  				morphTargetsNormal = [];
 12257  
 12258  				for ( var i = 0; i < morphNormalsLength; i ++ ) {
 12259  
 12260  					morphTargetsNormal[ i ] = [];
 12261  
 12262  				}
 12263  
 12264  				this.morphTargets.normal = morphTargetsNormal;
 12265  
 12266  			}
 12267  
 12268  			// skins
 12269  
 12270  			var skinIndices = geometry.skinIndices;
 12271  			var skinWeights = geometry.skinWeights;
 12272  
 12273  			var hasSkinIndices = skinIndices.length === vertices.length;
 12274  			var hasSkinWeights = skinWeights.length === vertices.length;
 12275  
 12276  			//
 12277  
 12278  			for ( var i = 0; i < faces.length; i ++ ) {
 12279  
 12280  				var face = faces[ i ];
 12281  
 12282  				this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] );
 12283  
 12284  				var vertexNormals = face.vertexNormals;
 12285  
 12286  				if ( vertexNormals.length === 3 ) {
 12287  
 12288  					this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] );
 12289  
 12290  				} else {
 12291  
 12292  					var normal = face.normal;
 12293  
 12294  					this.normals.push( normal, normal, normal );
 12295  
 12296  				}
 12297  
 12298  				var vertexColors = face.vertexColors;
 12299  
 12300  				if ( vertexColors.length === 3 ) {
 12301  
 12302  					this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );
 12303  
 12304  				} else {
 12305  
 12306  					var color = face.color;
 12307  
 12308  					this.colors.push( color, color, color );
 12309  
 12310  				}
 12311  
 12312  				if ( hasFaceVertexUv === true ) {
 12313  
 12314  					var vertexUvs = faceVertexUvs[ 0 ][ i ];
 12315  
 12316  					if ( vertexUvs !== undefined ) {
 12317  
 12318  						this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );
 12319  
 12320  					} else {
 12321  
 12322  						console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i );
 12323  
 12324  						this.uvs.push( new Vector2(), new Vector2(), new Vector2() );
 12325  
 12326  					}
 12327  
 12328  				}
 12329  
 12330  				if ( hasFaceVertexUv2 === true ) {
 12331  
 12332  					var vertexUvs = faceVertexUvs[ 1 ][ i ];
 12333  
 12334  					if ( vertexUvs !== undefined ) {
 12335  
 12336  						this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );
 12337  
 12338  					} else {
 12339  
 12340  						console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i );
 12341  
 12342  						this.uvs2.push( new Vector2(), new Vector2(), new Vector2() );
 12343  
 12344  					}
 12345  
 12346  				}
 12347  
 12348  				// morphs
 12349  
 12350  				for ( var j = 0; j < morphTargetsLength; j ++ ) {
 12351  
 12352  					var morphTarget = morphTargets[ j ].vertices;
 12353  
 12354  					morphTargetsPosition[ j ].push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] );
 12355  
 12356  				}
 12357  
 12358  				for ( var j = 0; j < morphNormalsLength; j ++ ) {
 12359  
 12360  					var morphNormal = morphNormals[ j ].vertexNormals[ i ];
 12361  
 12362  					morphTargetsNormal[ j ].push( morphNormal.a, morphNormal.b, morphNormal.c );
 12363  
 12364  				}
 12365  
 12366  				// skins
 12367  
 12368  				if ( hasSkinIndices ) {
 12369  
 12370  					this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] );
 12371  
 12372  				}
 12373  
 12374  				if ( hasSkinWeights ) {
 12375  
 12376  					this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] );
 12377  
 12378  				}
 12379  
 12380  			}
 12381  
 12382  			this.computeGroups( geometry );
 12383  
 12384  			this.verticesNeedUpdate = geometry.verticesNeedUpdate;
 12385  			this.normalsNeedUpdate = geometry.normalsNeedUpdate;
 12386  			this.colorsNeedUpdate = geometry.colorsNeedUpdate;
 12387  			this.uvsNeedUpdate = geometry.uvsNeedUpdate;
 12388  			this.groupsNeedUpdate = geometry.groupsNeedUpdate;
 12389  
 12390  			return this;
 12391  
 12392  		}
 12393  
 12394  	} );
 12395  
 12396  	// http://stackoverflow.com/questions/1669190/javascript-min-max-array-values/13440842#13440842
 12397  
 12398  	function arrayMax( array ) {
 12399  
 12400  		var length = array.length, max = - Infinity;
 12401  
 12402  		while ( length -- ) {
 12403  
 12404  			if ( array[ length ] > max ) {
 12405  
 12406  				max = array[ length ];
 12407  
 12408  			}
 12409  
 12410  		}
 12411  
 12412  		return max;
 12413  
 12414  	}
 12415  
 12416  	/**
 12417  	 * @author mrdoob / http://mrdoob.com/
 12418  	 * @author kile / http://kile.stravaganza.org/
 12419  	 * @author alteredq / http://alteredqualia.com/
 12420  	 * @author mikael emtinger / http://gomo.se/
 12421  	 * @author zz85 / http://www.lab4games.net/zz85/blog
 12422  	 * @author bhouston / http://clara.io
 12423  	 */
 12424  
 12425  	var count = 0;
 12426  	function GeometryIdCount() { return count++; }
 12427  
 12428  	function Geometry() {
 12429  
 12430  		Object.defineProperty( this, 'id', { value: GeometryIdCount() } );
 12431  
 12432  		this.uuid = _Math.generateUUID();
 12433  
 12434  		this.name = '';
 12435  		this.type = 'Geometry';
 12436  
 12437  		this.vertices = [];
 12438  		this.colors = [];
 12439  		this.faces = [];
 12440  		this.faceVertexUvs = [[]];
 12441  
 12442  		this.morphTargets = [];
 12443  		this.morphNormals = [];
 12444  
 12445  		this.skinWeights = [];
 12446  		this.skinIndices = [];
 12447  
 12448  		this.lineDistances = [];
 12449  
 12450  		this.boundingBox = null;
 12451  		this.boundingSphere = null;
 12452  
 12453  		// update flags
 12454  
 12455  		this.elementsNeedUpdate = false;
 12456  		this.verticesNeedUpdate = false;
 12457  		this.uvsNeedUpdate = false;
 12458  		this.normalsNeedUpdate = false;
 12459  		this.colorsNeedUpdate = false;
 12460  		this.lineDistancesNeedUpdate = false;
 12461  		this.groupsNeedUpdate = false;
 12462  
 12463  	}
 12464  
 12465  	Geometry.prototype = {
 12466  
 12467  		constructor: Geometry,
 12468  
 12469  		isGeometry: true,
 12470  
 12471  		applyMatrix: function ( matrix ) {
 12472  
 12473  			var normalMatrix = new Matrix3().getNormalMatrix( matrix );
 12474  
 12475  			for ( var i = 0, il = this.vertices.length; i < il; i ++ ) {
 12476  
 12477  				var vertex = this.vertices[ i ];
 12478  				vertex.applyMatrix4( matrix );
 12479  
 12480  			}
 12481  
 12482  			for ( var i = 0, il = this.faces.length; i < il; i ++ ) {
 12483  
 12484  				var face = this.faces[ i ];
 12485  				face.normal.applyMatrix3( normalMatrix ).normalize();
 12486  
 12487  				for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
 12488  
 12489  					face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize();
 12490  
 12491  				}
 12492  
 12493  			}
 12494  
 12495  			if ( this.boundingBox !== null ) {
 12496  
 12497  				this.computeBoundingBox();
 12498  
 12499  			}
 12500  
 12501  			if ( this.boundingSphere !== null ) {
 12502  
 12503  				this.computeBoundingSphere();
 12504  
 12505  			}
 12506  
 12507  			this.verticesNeedUpdate = true;
 12508  			this.normalsNeedUpdate = true;
 12509  
 12510  			return this;
 12511  
 12512  		},
 12513  
 12514  		rotateX: function () {
 12515  
 12516  			// rotate geometry around world x-axis
 12517  
 12518  			var m1;
 12519  
 12520  			return function rotateX( angle ) {
 12521  
 12522  				if ( m1 === undefined ) m1 = new Matrix4();
 12523  
 12524  				m1.makeRotationX( angle );
 12525  
 12526  				this.applyMatrix( m1 );
 12527  
 12528  				return this;
 12529  
 12530  			};
 12531  
 12532  		}(),
 12533  
 12534  		rotateY: function () {
 12535  
 12536  			// rotate geometry around world y-axis
 12537  
 12538  			var m1;
 12539  
 12540  			return function rotateY( angle ) {
 12541  
 12542  				if ( m1 === undefined ) m1 = new Matrix4();
 12543  
 12544  				m1.makeRotationY( angle );
 12545  
 12546  				this.applyMatrix( m1 );
 12547  
 12548  				return this;
 12549  
 12550  			};
 12551  
 12552  		}(),
 12553  
 12554  		rotateZ: function () {
 12555  
 12556  			// rotate geometry around world z-axis
 12557  
 12558  			var m1;
 12559  
 12560  			return function rotateZ( angle ) {
 12561  
 12562  				if ( m1 === undefined ) m1 = new Matrix4();
 12563  
 12564  				m1.makeRotationZ( angle );
 12565  
 12566  				this.applyMatrix( m1 );
 12567  
 12568  				return this;
 12569  
 12570  			};
 12571  
 12572  		}(),
 12573  
 12574  		translate: function () {
 12575  
 12576  			// translate geometry
 12577  
 12578  			var m1;
 12579  
 12580  			return function translate( x, y, z ) {
 12581  
 12582  				if ( m1 === undefined ) m1 = new Matrix4();
 12583  
 12584  				m1.makeTranslation( x, y, z );
 12585  
 12586  				this.applyMatrix( m1 );
 12587  
 12588  				return this;
 12589  
 12590  			};
 12591  
 12592  		}(),
 12593  
 12594  		scale: function () {
 12595  
 12596  			// scale geometry
 12597  
 12598  			var m1;
 12599  
 12600  			return function scale( x, y, z ) {
 12601  
 12602  				if ( m1 === undefined ) m1 = new Matrix4();
 12603  
 12604  				m1.makeScale( x, y, z );
 12605  
 12606  				this.applyMatrix( m1 );
 12607  
 12608  				return this;
 12609  
 12610  			};
 12611  
 12612  		}(),
 12613  
 12614  		lookAt: function () {
 12615  
 12616  			var obj;
 12617  
 12618  			return function lookAt( vector ) {
 12619  
 12620  				if ( obj === undefined ) obj = new Object3D();
 12621  
 12622  				obj.lookAt( vector );
 12623  
 12624  				obj.updateMatrix();
 12625  
 12626  				this.applyMatrix( obj.matrix );
 12627  
 12628  			};
 12629  
 12630  		}(),
 12631  
 12632  		fromBufferGeometry: function ( geometry ) {
 12633  
 12634  			var scope = this;
 12635  
 12636  			var indices = geometry.index !== null ? geometry.index.array : undefined;
 12637  			var attributes = geometry.attributes;
 12638  
 12639  			var positions = attributes.position.array;
 12640  			var normals = attributes.normal !== undefined ? attributes.normal.array : undefined;
 12641  			var colors = attributes.color !== undefined ? attributes.color.array : undefined;
 12642  			var uvs = attributes.uv !== undefined ? attributes.uv.array : undefined;
 12643  			var uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined;
 12644  
 12645  			if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = [];
 12646  
 12647  			var tempNormals = [];
 12648  			var tempUVs = [];
 12649  			var tempUVs2 = [];
 12650  
 12651  			for ( var i = 0, j = 0; i < positions.length; i += 3, j += 2 ) {
 12652  
 12653  				scope.vertices.push( new Vector3( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ) );
 12654  
 12655  				if ( normals !== undefined ) {
 12656  
 12657  					tempNormals.push( new Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) );
 12658  
 12659  				}
 12660  
 12661  				if ( colors !== undefined ) {
 12662  
 12663  					scope.colors.push( new Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) );
 12664  
 12665  				}
 12666  
 12667  				if ( uvs !== undefined ) {
 12668  
 12669  					tempUVs.push( new Vector2( uvs[ j ], uvs[ j + 1 ] ) );
 12670  
 12671  				}
 12672  
 12673  				if ( uvs2 !== undefined ) {
 12674  
 12675  					tempUVs2.push( new Vector2( uvs2[ j ], uvs2[ j + 1 ] ) );
 12676  
 12677  				}
 12678  
 12679  			}
 12680  
 12681  			function addFace( a, b, c, materialIndex ) {
 12682  
 12683  				var vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : [];
 12684  				var vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : [];
 12685  
 12686  				var face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex );
 12687  
 12688  				scope.faces.push( face );
 12689  
 12690  				if ( uvs !== undefined ) {
 12691  
 12692  					scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] );
 12693  
 12694  				}
 12695  
 12696  				if ( uvs2 !== undefined ) {
 12697  
 12698  					scope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] );
 12699  
 12700  				}
 12701  
 12702  			}
 12703  
 12704  			if ( indices !== undefined ) {
 12705  
 12706  				var groups = geometry.groups;
 12707  
 12708  				if ( groups.length > 0 ) {
 12709  
 12710  					for ( var i = 0; i < groups.length; i ++ ) {
 12711  
 12712  						var group = groups[ i ];
 12713  
 12714  						var start = group.start;
 12715  						var count = group.count;
 12716  
 12717  						for ( var j = start, jl = start + count; j < jl; j += 3 ) {
 12718  
 12719  							addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex );
 12720  
 12721  						}
 12722  
 12723  					}
 12724  
 12725  				} else {
 12726  
 12727  					for ( var i = 0; i < indices.length; i += 3 ) {
 12728  
 12729  						addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
 12730  
 12731  					}
 12732  
 12733  				}
 12734  
 12735  			} else {
 12736  
 12737  				for ( var i = 0; i < positions.length / 3; i += 3 ) {
 12738  
 12739  					addFace( i, i + 1, i + 2 );
 12740  
 12741  				}
 12742  
 12743  			}
 12744  
 12745  			this.computeFaceNormals();
 12746  
 12747  			if ( geometry.boundingBox !== null ) {
 12748  
 12749  				this.boundingBox = geometry.boundingBox.clone();
 12750  
 12751  			}
 12752  
 12753  			if ( geometry.boundingSphere !== null ) {
 12754  
 12755  				this.boundingSphere = geometry.boundingSphere.clone();
 12756  
 12757  			}
 12758  
 12759  			return this;
 12760  
 12761  		},
 12762  
 12763  		center: function () {
 12764  
 12765  			this.computeBoundingBox();
 12766  
 12767  			var offset = this.boundingBox.getCenter().negate();
 12768  
 12769  			this.translate( offset.x, offset.y, offset.z );
 12770  
 12771  			return offset;
 12772  
 12773  		},
 12774  
 12775  		normalize: function () {
 12776  
 12777  			this.computeBoundingSphere();
 12778  
 12779  			var center = this.boundingSphere.center;
 12780  			var radius = this.boundingSphere.radius;
 12781  
 12782  			var s = radius === 0 ? 1 : 1.0 / radius;
 12783  
 12784  			var matrix = new Matrix4();
 12785  			matrix.set(
 12786  				s, 0, 0, - s * center.x,
 12787  				0, s, 0, - s * center.y,
 12788  				0, 0, s, - s * center.z,
 12789  				0, 0, 0, 1
 12790  			);
 12791  
 12792  			this.applyMatrix( matrix );
 12793  
 12794  			return this;
 12795  
 12796  		},
 12797  
 12798  		computeFaceNormals: function () {
 12799  
 12800  			var cb = new Vector3(), ab = new Vector3();
 12801  
 12802  			for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) {
 12803  
 12804  				var face = this.faces[ f ];
 12805  
 12806  				var vA = this.vertices[ face.a ];
 12807  				var vB = this.vertices[ face.b ];
 12808  				var vC = this.vertices[ face.c ];
 12809  
 12810  				cb.subVectors( vC, vB );
 12811  				ab.subVectors( vA, vB );
 12812  				cb.cross( ab );
 12813  
 12814  				cb.normalize();
 12815  
 12816  				face.normal.copy( cb );
 12817  
 12818  			}
 12819  
 12820  		},
 12821  
 12822  		computeVertexNormals: function ( areaWeighted ) {
 12823  
 12824  			if ( areaWeighted === undefined ) areaWeighted = true;
 12825  
 12826  			var v, vl, f, fl, face, vertices;
 12827  
 12828  			vertices = new Array( this.vertices.length );
 12829  
 12830  			for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
 12831  
 12832  				vertices[ v ] = new Vector3();
 12833  
 12834  			}
 12835  
 12836  			if ( areaWeighted ) {
 12837  
 12838  				// vertex normals weighted by triangle areas
 12839  				// http://www.iquilezles.org/www/articles/normals/normals.htm
 12840  
 12841  				var vA, vB, vC;
 12842  				var cb = new Vector3(), ab = new Vector3();
 12843  
 12844  				for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
 12845  
 12846  					face = this.faces[ f ];
 12847  
 12848  					vA = this.vertices[ face.a ];
 12849  					vB = this.vertices[ face.b ];
 12850  					vC = this.vertices[ face.c ];
 12851  
 12852  					cb.subVectors( vC, vB );
 12853  					ab.subVectors( vA, vB );
 12854  					cb.cross( ab );
 12855  
 12856  					vertices[ face.a ].add( cb );
 12857  					vertices[ face.b ].add( cb );
 12858  					vertices[ face.c ].add( cb );
 12859  
 12860  				}
 12861  
 12862  			} else {
 12863  
 12864  				this.computeFaceNormals();
 12865  
 12866  				for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
 12867  
 12868  					face = this.faces[ f ];
 12869  
 12870  					vertices[ face.a ].add( face.normal );
 12871  					vertices[ face.b ].add( face.normal );
 12872  					vertices[ face.c ].add( face.normal );
 12873  
 12874  				}
 12875  
 12876  			}
 12877  
 12878  			for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
 12879  
 12880  				vertices[ v ].normalize();
 12881  
 12882  			}
 12883  
 12884  			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
 12885  
 12886  				face = this.faces[ f ];
 12887  
 12888  				var vertexNormals = face.vertexNormals;
 12889  
 12890  				if ( vertexNormals.length === 3 ) {
 12891  
 12892  					vertexNormals[ 0 ].copy( vertices[ face.a ] );
 12893  					vertexNormals[ 1 ].copy( vertices[ face.b ] );
 12894  					vertexNormals[ 2 ].copy( vertices[ face.c ] );
 12895  
 12896  				} else {
 12897  
 12898  					vertexNormals[ 0 ] = vertices[ face.a ].clone();
 12899  					vertexNormals[ 1 ] = vertices[ face.b ].clone();
 12900  					vertexNormals[ 2 ] = vertices[ face.c ].clone();
 12901  
 12902  				}
 12903  
 12904  			}
 12905  
 12906  			if ( this.faces.length > 0 ) {
 12907  
 12908  				this.normalsNeedUpdate = true;
 12909  
 12910  			}
 12911  
 12912  		},
 12913  
 12914  		computeFlatVertexNormals: function () {
 12915  
 12916  			var f, fl, face;
 12917  
 12918  			this.computeFaceNormals();
 12919  
 12920  			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
 12921  
 12922  				face = this.faces[ f ];
 12923  
 12924  				var vertexNormals = face.vertexNormals;
 12925  
 12926  				if ( vertexNormals.length === 3 ) {
 12927  
 12928  					vertexNormals[ 0 ].copy( face.normal );
 12929  					vertexNormals[ 1 ].copy( face.normal );
 12930  					vertexNormals[ 2 ].copy( face.normal );
 12931  
 12932  				} else {
 12933  
 12934  					vertexNormals[ 0 ] = face.normal.clone();
 12935  					vertexNormals[ 1 ] = face.normal.clone();
 12936  					vertexNormals[ 2 ] = face.normal.clone();
 12937  
 12938  				}
 12939  
 12940  			}
 12941  
 12942  			if ( this.faces.length > 0 ) {
 12943  
 12944  				this.normalsNeedUpdate = true;
 12945  
 12946  			}
 12947  
 12948  		},
 12949  
 12950  		computeMorphNormals: function () {
 12951  
 12952  			var i, il, f, fl, face;
 12953  
 12954  			// save original normals
 12955  			// - create temp variables on first access
 12956  			//   otherwise just copy (for faster repeated calls)
 12957  
 12958  			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
 12959  
 12960  				face = this.faces[ f ];
 12961  
 12962  				if ( ! face.__originalFaceNormal ) {
 12963  
 12964  					face.__originalFaceNormal = face.normal.clone();
 12965  
 12966  				} else {
 12967  
 12968  					face.__originalFaceNormal.copy( face.normal );
 12969  
 12970  				}
 12971  
 12972  				if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];
 12973  
 12974  				for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) {
 12975  
 12976  					if ( ! face.__originalVertexNormals[ i ] ) {
 12977  
 12978  						face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();
 12979  
 12980  					} else {
 12981  
 12982  						face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );
 12983  
 12984  					}
 12985  
 12986  				}
 12987  
 12988  			}
 12989  
 12990  			// use temp geometry to compute face and vertex normals for each morph
 12991  
 12992  			var tmpGeo = new Geometry();
 12993  			tmpGeo.faces = this.faces;
 12994  
 12995  			for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) {
 12996  
 12997  				// create on first access
 12998  
 12999  				if ( ! this.morphNormals[ i ] ) {
 13000  
 13001  					this.morphNormals[ i ] = {};
 13002  					this.morphNormals[ i ].faceNormals = [];
 13003  					this.morphNormals[ i ].vertexNormals = [];
 13004  
 13005  					var dstNormalsFace = this.morphNormals[ i ].faceNormals;
 13006  					var dstNormalsVertex = this.morphNormals[ i ].vertexNormals;
 13007  
 13008  					var faceNormal, vertexNormals;
 13009  
 13010  					for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
 13011  
 13012  						faceNormal = new Vector3();
 13013  						vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() };
 13014  
 13015  						dstNormalsFace.push( faceNormal );
 13016  						dstNormalsVertex.push( vertexNormals );
 13017  
 13018  					}
 13019  
 13020  				}
 13021  
 13022  				var morphNormals = this.morphNormals[ i ];
 13023  
 13024  				// set vertices to morph target
 13025  
 13026  				tmpGeo.vertices = this.morphTargets[ i ].vertices;
 13027  
 13028  				// compute morph normals
 13029  
 13030  				tmpGeo.computeFaceNormals();
 13031  				tmpGeo.computeVertexNormals();
 13032  
 13033  				// store morph normals
 13034  
 13035  				var faceNormal, vertexNormals;
 13036  
 13037  				for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
 13038  
 13039  					face = this.faces[ f ];
 13040  
 13041  					faceNormal = morphNormals.faceNormals[ f ];
 13042  					vertexNormals = morphNormals.vertexNormals[ f ];
 13043  
 13044  					faceNormal.copy( face.normal );
 13045  
 13046  					vertexNormals.a.copy( face.vertexNormals[ 0 ] );
 13047  					vertexNormals.b.copy( face.vertexNormals[ 1 ] );
 13048  					vertexNormals.c.copy( face.vertexNormals[ 2 ] );
 13049  
 13050  				}
 13051  
 13052  			}
 13053  
 13054  			// restore original normals
 13055  
 13056  			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
 13057  
 13058  				face = this.faces[ f ];
 13059  
 13060  				face.normal = face.__originalFaceNormal;
 13061  				face.vertexNormals = face.__originalVertexNormals;
 13062  
 13063  			}
 13064  
 13065  		},
 13066  
 13067  		computeLineDistances: function () {
 13068  
 13069  			var d = 0;
 13070  			var vertices = this.vertices;
 13071  
 13072  			for ( var i = 0, il = vertices.length; i < il; i ++ ) {
 13073  
 13074  				if ( i > 0 ) {
 13075  
 13076  					d += vertices[ i ].distanceTo( vertices[ i - 1 ] );
 13077  
 13078  				}
 13079  
 13080  				this.lineDistances[ i ] = d;
 13081  
 13082  			}
 13083  
 13084  		},
 13085  
 13086  		computeBoundingBox: function () {
 13087  
 13088  			if ( this.boundingBox === null ) {
 13089  
 13090  				this.boundingBox = new Box3();
 13091  
 13092  			}
 13093  
 13094  			this.boundingBox.setFromPoints( this.vertices );
 13095  
 13096  		},
 13097  
 13098  		computeBoundingSphere: function () {
 13099  
 13100  			if ( this.boundingSphere === null ) {
 13101  
 13102  				this.boundingSphere = new Sphere();
 13103  
 13104  			}
 13105  
 13106  			this.boundingSphere.setFromPoints( this.vertices );
 13107  
 13108  		},
 13109  
 13110  		merge: function ( geometry, matrix, materialIndexOffset ) {
 13111  
 13112  			if ( ( geometry && geometry.isGeometry ) === false ) {
 13113  
 13114  				console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry );
 13115  				return;
 13116  
 13117  			}
 13118  
 13119  			var normalMatrix,
 13120  			vertexOffset = this.vertices.length,
 13121  			vertices1 = this.vertices,
 13122  			vertices2 = geometry.vertices,
 13123  			faces1 = this.faces,
 13124  			faces2 = geometry.faces,
 13125  			uvs1 = this.faceVertexUvs[ 0 ],
 13126  			uvs2 = geometry.faceVertexUvs[ 0 ],
 13127  			colors1 = this.colors,
 13128  			colors2 = geometry.colors;
 13129  
 13130  			if ( materialIndexOffset === undefined ) materialIndexOffset = 0;
 13131  
 13132  			if ( matrix !== undefined ) {
 13133  
 13134  				normalMatrix = new Matrix3().getNormalMatrix( matrix );
 13135  
 13136  			}
 13137  
 13138  			// vertices
 13139  
 13140  			for ( var i = 0, il = vertices2.length; i < il; i ++ ) {
 13141  
 13142  				var vertex = vertices2[ i ];
 13143  
 13144  				var vertexCopy = vertex.clone();
 13145  
 13146  				if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix );
 13147  
 13148  				vertices1.push( vertexCopy );
 13149  
 13150  			}
 13151  
 13152  			// colors
 13153  
 13154  			for ( var i = 0, il = colors2.length; i < il; i ++ ) {
 13155  
 13156  				colors1.push( colors2[ i ].clone() );
 13157  
 13158  			}
 13159  
 13160  			// faces
 13161  
 13162  			for ( i = 0, il = faces2.length; i < il; i ++ ) {
 13163  
 13164  				var face = faces2[ i ], faceCopy, normal, color,
 13165  				faceVertexNormals = face.vertexNormals,
 13166  				faceVertexColors = face.vertexColors;
 13167  
 13168  				faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
 13169  				faceCopy.normal.copy( face.normal );
 13170  
 13171  				if ( normalMatrix !== undefined ) {
 13172  
 13173  					faceCopy.normal.applyMatrix3( normalMatrix ).normalize();
 13174  
 13175  				}
 13176  
 13177  				for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
 13178  
 13179  					normal = faceVertexNormals[ j ].clone();
 13180  
 13181  					if ( normalMatrix !== undefined ) {
 13182  
 13183  						normal.applyMatrix3( normalMatrix ).normalize();
 13184  
 13185  					}
 13186  
 13187  					faceCopy.vertexNormals.push( normal );
 13188  
 13189  				}
 13190  
 13191  				faceCopy.color.copy( face.color );
 13192  
 13193  				for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
 13194  
 13195  					color = faceVertexColors[ j ];
 13196  					faceCopy.vertexColors.push( color.clone() );
 13197  
 13198  				}
 13199  
 13200  				faceCopy.materialIndex = face.materialIndex + materialIndexOffset;
 13201  
 13202  				faces1.push( faceCopy );
 13203  
 13204  			}
 13205  
 13206  			// uvs
 13207  
 13208  			for ( i = 0, il = uvs2.length; i < il; i ++ ) {
 13209  
 13210  				var uv = uvs2[ i ], uvCopy = [];
 13211  
 13212  				if ( uv === undefined ) {
 13213  
 13214  					continue;
 13215  
 13216  				}
 13217  
 13218  				for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
 13219  
 13220  					uvCopy.push( uv[ j ].clone() );
 13221  
 13222  				}
 13223  
 13224  				uvs1.push( uvCopy );
 13225  
 13226  			}
 13227  
 13228  		},
 13229  
 13230  		mergeMesh: function ( mesh ) {
 13231  
 13232  			if ( ( mesh && mesh.isMesh ) === false ) {
 13233  
 13234  				console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh );
 13235  				return;
 13236  
 13237  			}
 13238  
 13239  			mesh.matrixAutoUpdate && mesh.updateMatrix();
 13240  
 13241  			this.merge( mesh.geometry, mesh.matrix );
 13242  
 13243  		},
 13244  
 13245  		/*
 13246  		 * Checks for duplicate vertices with hashmap.
 13247  		 * Duplicated vertices are removed
 13248  		 * and faces' vertices are updated.
 13249  		 */
 13250  
 13251  		mergeVertices: function () {
 13252  
 13253  			var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique)
 13254  			var unique = [], changes = [];
 13255  
 13256  			var v, key;
 13257  			var precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001
 13258  			var precision = Math.pow( 10, precisionPoints );
 13259  			var i, il, face;
 13260  			var indices, j, jl;
 13261  
 13262  			for ( i = 0, il = this.vertices.length; i < il; i ++ ) {
 13263  
 13264  				v = this.vertices[ i ];
 13265  				key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision );
 13266  
 13267  				if ( verticesMap[ key ] === undefined ) {
 13268  
 13269  					verticesMap[ key ] = i;
 13270  					unique.push( this.vertices[ i ] );
 13271  					changes[ i ] = unique.length - 1;
 13272  
 13273  				} else {
 13274  
 13275  					//console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);
 13276  					changes[ i ] = changes[ verticesMap[ key ] ];
 13277  
 13278  				}
 13279  
 13280  			}
 13281  
 13282  
 13283  			// if faces are completely degenerate after merging vertices, we
 13284  			// have to remove them from the geometry.
 13285  			var faceIndicesToRemove = [];
 13286  
 13287  			for ( i = 0, il = this.faces.length; i < il; i ++ ) {
 13288  
 13289  				face = this.faces[ i ];
 13290  
 13291  				face.a = changes[ face.a ];
 13292  				face.b = changes[ face.b ];
 13293  				face.c = changes[ face.c ];
 13294  
 13295  				indices = [ face.a, face.b, face.c ];
 13296  
 13297  				// if any duplicate vertices are found in a Face3
 13298  				// we have to remove the face as nothing can be saved
 13299  				for ( var n = 0; n < 3; n ++ ) {
 13300  
 13301  					if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) {
 13302  
 13303  						faceIndicesToRemove.push( i );
 13304  						break;
 13305  
 13306  					}
 13307  
 13308  				}
 13309  
 13310  			}
 13311  
 13312  			for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {
 13313  
 13314  				var idx = faceIndicesToRemove[ i ];
 13315  
 13316  				this.faces.splice( idx, 1 );
 13317  
 13318  				for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {
 13319  
 13320  					this.faceVertexUvs[ j ].splice( idx, 1 );
 13321  
 13322  				}
 13323  
 13324  			}
 13325  
 13326  			// Use unique set of vertices
 13327  
 13328  			var diff = this.vertices.length - unique.length;
 13329  			this.vertices = unique;
 13330  			return diff;
 13331  
 13332  		},
 13333  
 13334  		sortFacesByMaterialIndex: function () {
 13335  
 13336  			var faces = this.faces;
 13337  			var length = faces.length;
 13338  
 13339  			// tag faces
 13340  
 13341  			for ( var i = 0; i < length; i ++ ) {
 13342  
 13343  				faces[ i ]._id = i;
 13344  
 13345  			}
 13346  
 13347  			// sort faces
 13348  
 13349  			function materialIndexSort( a, b ) {
 13350  
 13351  				return a.materialIndex - b.materialIndex;
 13352  
 13353  			}
 13354  
 13355  			faces.sort( materialIndexSort );
 13356  
 13357  			// sort uvs
 13358  
 13359  			var uvs1 = this.faceVertexUvs[ 0 ];
 13360  			var uvs2 = this.faceVertexUvs[ 1 ];
 13361  
 13362  			var newUvs1, newUvs2;
 13363  
 13364  			if ( uvs1 && uvs1.length === length ) newUvs1 = [];
 13365  			if ( uvs2 && uvs2.length === length ) newUvs2 = [];
 13366  
 13367  			for ( var i = 0; i < length; i ++ ) {
 13368  
 13369  				var id = faces[ i ]._id;
 13370  
 13371  				if ( newUvs1 ) newUvs1.push( uvs1[ id ] );
 13372  				if ( newUvs2 ) newUvs2.push( uvs2[ id ] );
 13373  
 13374  			}
 13375  
 13376  			if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1;
 13377  			if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2;
 13378  
 13379  		},
 13380  
 13381  		toJSON: function () {
 13382  
 13383  			var data = {
 13384  				metadata: {
 13385  					version: 4.4,
 13386  					type: 'Geometry',
 13387  					generator: 'Geometry.toJSON'
 13388  				}
 13389  			};
 13390  
 13391  			// standard Geometry serialization
 13392  
 13393  			data.uuid = this.uuid;
 13394  			data.type = this.type;
 13395  			if ( this.name !== '' ) data.name = this.name;
 13396  
 13397  			if ( this.parameters !== undefined ) {
 13398  
 13399  				var parameters = this.parameters;
 13400  
 13401  				for ( var key in parameters ) {
 13402  
 13403  					if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
 13404  
 13405  				}
 13406  
 13407  				return data;
 13408  
 13409  			}
 13410  
 13411  			var vertices = [];
 13412  
 13413  			for ( var i = 0; i < this.vertices.length; i ++ ) {
 13414  
 13415  				var vertex = this.vertices[ i ];
 13416  				vertices.push( vertex.x, vertex.y, vertex.z );
 13417  
 13418  			}
 13419  
 13420  			var faces = [];
 13421  			var normals = [];
 13422  			var normalsHash = {};
 13423  			var colors = [];
 13424  			var colorsHash = {};
 13425  			var uvs = [];
 13426  			var uvsHash = {};
 13427  
 13428  			for ( var i = 0; i < this.faces.length; i ++ ) {
 13429  
 13430  				var face = this.faces[ i ];
 13431  
 13432  				var hasMaterial = true;
 13433  				var hasFaceUv = false; // deprecated
 13434  				var hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined;
 13435  				var hasFaceNormal = face.normal.length() > 0;
 13436  				var hasFaceVertexNormal = face.vertexNormals.length > 0;
 13437  				var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1;
 13438  				var hasFaceVertexColor = face.vertexColors.length > 0;
 13439  
 13440  				var faceType = 0;
 13441  
 13442  				faceType = setBit( faceType, 0, 0 ); // isQuad
 13443  				faceType = setBit( faceType, 1, hasMaterial );
 13444  				faceType = setBit( faceType, 2, hasFaceUv );
 13445  				faceType = setBit( faceType, 3, hasFaceVertexUv );
 13446  				faceType = setBit( faceType, 4, hasFaceNormal );
 13447  				faceType = setBit( faceType, 5, hasFaceVertexNormal );
 13448  				faceType = setBit( faceType, 6, hasFaceColor );
 13449  				faceType = setBit( faceType, 7, hasFaceVertexColor );
 13450  
 13451  				faces.push( faceType );
 13452  				faces.push( face.a, face.b, face.c );
 13453  				faces.push( face.materialIndex );
 13454  
 13455  				if ( hasFaceVertexUv ) {
 13456  
 13457  					var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ];
 13458  
 13459  					faces.push(
 13460  						getUvIndex( faceVertexUvs[ 0 ] ),
 13461  						getUvIndex( faceVertexUvs[ 1 ] ),
 13462  						getUvIndex( faceVertexUvs[ 2 ] )
 13463  					);
 13464  
 13465  				}
 13466  
 13467  				if ( hasFaceNormal ) {
 13468  
 13469  					faces.push( getNormalIndex( face.normal ) );
 13470  
 13471  				}
 13472  
 13473  				if ( hasFaceVertexNormal ) {
 13474  
 13475  					var vertexNormals = face.vertexNormals;
 13476  
 13477  					faces.push(
 13478  						getNormalIndex( vertexNormals[ 0 ] ),
 13479  						getNormalIndex( vertexNormals[ 1 ] ),
 13480  						getNormalIndex( vertexNormals[ 2 ] )
 13481  					);
 13482  
 13483  				}
 13484  
 13485  				if ( hasFaceColor ) {
 13486  
 13487  					faces.push( getColorIndex( face.color ) );
 13488  
 13489  				}
 13490  
 13491  				if ( hasFaceVertexColor ) {
 13492  
 13493  					var vertexColors = face.vertexColors;
 13494  
 13495  					faces.push(
 13496  						getColorIndex( vertexColors[ 0 ] ),
 13497  						getColorIndex( vertexColors[ 1 ] ),
 13498  						getColorIndex( vertexColors[ 2 ] )
 13499  					);
 13500  
 13501  				}
 13502  
 13503  			}
 13504  
 13505  			function setBit( value, position, enabled ) {
 13506  
 13507  				return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) );
 13508  
 13509  			}
 13510  
 13511  			function getNormalIndex( normal ) {
 13512  
 13513  				var hash = normal.x.toString() + normal.y.toString() + normal.z.toString();
 13514  
 13515  				if ( normalsHash[ hash ] !== undefined ) {
 13516  
 13517  					return normalsHash[ hash ];
 13518  
 13519  				}
 13520  
 13521  				normalsHash[ hash ] = normals.length / 3;
 13522  				normals.push( normal.x, normal.y, normal.z );
 13523  
 13524  				return normalsHash[ hash ];
 13525  
 13526  			}
 13527  
 13528  			function getColorIndex( color ) {
 13529  
 13530  				var hash = color.r.toString() + color.g.toString() + color.b.toString();
 13531  
 13532  				if ( colorsHash[ hash ] !== undefined ) {
 13533  
 13534  					return colorsHash[ hash ];
 13535  
 13536  				}
 13537  
 13538  				colorsHash[ hash ] = colors.length;
 13539  				colors.push( color.getHex() );
 13540  
 13541  				return colorsHash[ hash ];
 13542  
 13543  			}
 13544  
 13545  			function getUvIndex( uv ) {
 13546  
 13547  				var hash = uv.x.toString() + uv.y.toString();
 13548  
 13549  				if ( uvsHash[ hash ] !== undefined ) {
 13550  
 13551  					return uvsHash[ hash ];
 13552  
 13553  				}
 13554  
 13555  				uvsHash[ hash ] = uvs.length / 2;
 13556  				uvs.push( uv.x, uv.y );
 13557  
 13558  				return uvsHash[ hash ];
 13559  
 13560  			}
 13561  
 13562  			data.data = {};
 13563  
 13564  			data.data.vertices = vertices;
 13565  			data.data.normals = normals;
 13566  			if ( colors.length > 0 ) data.data.colors = colors;
 13567  			if ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility
 13568  			data.data.faces = faces;
 13569  
 13570  			return data;
 13571  
 13572  		},
 13573  
 13574  		clone: function () {
 13575  
 13576  			/*
 13577  			// Handle primitives
 13578  
 13579  			var parameters = this.parameters;
 13580  
 13581  			if ( parameters !== undefined ) {
 13582  
 13583  				var values = [];
 13584  
 13585  				for ( var key in parameters ) {
 13586  
 13587  					values.push( parameters[ key ] );
 13588  
 13589  				}
 13590  
 13591  				var geometry = Object.create( this.constructor.prototype );
 13592  				this.constructor.apply( geometry, values );
 13593  				return geometry;
 13594  
 13595  			}
 13596  
 13597  			return new this.constructor().copy( this );
 13598  			*/
 13599  
 13600  			return new Geometry().copy( this );
 13601  
 13602  		},
 13603  
 13604  		copy: function ( source ) {
 13605  
 13606  			var i, il, j, jl, k, kl;
 13607  
 13608  			// reset
 13609  
 13610  			this.vertices = [];
 13611  			this.colors = [];
 13612  			this.faces = [];
 13613  			this.faceVertexUvs = [[]];
 13614  			this.morphTargets = [];
 13615  			this.morphNormals = [];
 13616  			this.skinWeights = [];
 13617  			this.skinIndices = [];
 13618  			this.lineDistances = [];
 13619  			this.boundingBox = null;
 13620  			this.boundingSphere = null;
 13621  
 13622  			// name
 13623  
 13624  			this.name = source.name;
 13625  
 13626  			// vertices
 13627  
 13628  			var vertices = source.vertices;
 13629  
 13630  			for ( i = 0, il = vertices.length; i < il; i ++ ) {
 13631  
 13632  				this.vertices.push( vertices[ i ].clone() );
 13633  
 13634  			}
 13635  
 13636  			// colors
 13637  
 13638  			var colors = source.colors;
 13639  
 13640  			for ( i = 0, il = colors.length; i < il; i ++ ) {
 13641  
 13642  				this.colors.push( colors[ i ].clone() );
 13643  
 13644  			}
 13645  
 13646  			// faces
 13647  
 13648  			var faces = source.faces;
 13649  
 13650  			for ( i = 0, il = faces.length; i < il; i ++ ) {
 13651  
 13652  				this.faces.push( faces[ i ].clone() );
 13653  
 13654  			}
 13655  
 13656  			// face vertex uvs
 13657  
 13658  			for ( i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) {
 13659  
 13660  				var faceVertexUvs = source.faceVertexUvs[ i ];
 13661  
 13662  				if ( this.faceVertexUvs[ i ] === undefined ) {
 13663  
 13664  					this.faceVertexUvs[ i ] = [];
 13665  
 13666  				}
 13667  
 13668  				for ( j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) {
 13669  
 13670  					var uvs = faceVertexUvs[ j ], uvsCopy = [];
 13671  
 13672  					for ( k = 0, kl = uvs.length; k < kl; k ++ ) {
 13673  
 13674  						var uv = uvs[ k ];
 13675  
 13676  						uvsCopy.push( uv.clone() );
 13677  
 13678  					}
 13679  
 13680  					this.faceVertexUvs[ i ].push( uvsCopy );
 13681  
 13682  				}
 13683  
 13684  			}
 13685  
 13686  			// morph targets
 13687  
 13688  			var morphTargets = source.morphTargets;
 13689  
 13690  			for ( i = 0, il = morphTargets.length; i < il; i ++ ) {
 13691  
 13692  				var morphTarget = {};
 13693  				morphTarget.name = morphTargets[ i ].name;
 13694  
 13695  				// vertices
 13696  
 13697  				if ( morphTargets[ i ].vertices !== undefined ) {
 13698  
 13699  					morphTarget.vertices = [];
 13700  
 13701  					for ( j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) {
 13702  
 13703  						morphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() );
 13704  
 13705  					}
 13706  
 13707  				}
 13708  
 13709  				// normals
 13710  
 13711  				if ( morphTargets[ i ].normals !== undefined ) {
 13712  
 13713  					morphTarget.normals = [];
 13714  
 13715  					for ( j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) {
 13716  
 13717  						morphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() );
 13718  
 13719  					}
 13720  
 13721  				}
 13722  
 13723  				this.morphTargets.push( morphTarget );
 13724  
 13725  			}
 13726  
 13727  			// morph normals
 13728  
 13729  			var morphNormals = source.morphNormals;
 13730  
 13731  			for ( i = 0, il = morphNormals.length; i < il; i ++ ) {
 13732  
 13733  				var morphNormal = {};
 13734  
 13735  				// vertex normals
 13736  
 13737  				if ( morphNormals[ i ].vertexNormals !== undefined ) {
 13738  
 13739  					morphNormal.vertexNormals = [];
 13740  
 13741  					for ( j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) {
 13742  
 13743  						var srcVertexNormal = morphNormals[ i ].vertexNormals[ j ];
 13744  						var destVertexNormal = {};
 13745  
 13746  						destVertexNormal.a = srcVertexNormal.a.clone();
 13747  						destVertexNormal.b = srcVertexNormal.b.clone();
 13748  						destVertexNormal.c = srcVertexNormal.c.clone();
 13749  
 13750  						morphNormal.vertexNormals.push( destVertexNormal );
 13751  
 13752  					}
 13753  
 13754  				}
 13755  
 13756  				// face normals
 13757  
 13758  				if ( morphNormals[ i ].faceNormals !== undefined ) {
 13759  
 13760  					morphNormal.faceNormals = [];
 13761  
 13762  					for ( j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) {
 13763  
 13764  						morphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() );
 13765  
 13766  					}
 13767  
 13768  				}
 13769  
 13770  				this.morphNormals.push( morphNormal );
 13771  
 13772  			}
 13773  
 13774  			// skin weights
 13775  
 13776  			var skinWeights = source.skinWeights;
 13777  
 13778  			for ( i = 0, il = skinWeights.length; i < il; i ++ ) {
 13779  
 13780  				this.skinWeights.push( skinWeights[ i ].clone() );
 13781  
 13782  			}
 13783  
 13784  			// skin indices
 13785  
 13786  			var skinIndices = source.skinIndices;
 13787  
 13788  			for ( i = 0, il = skinIndices.length; i < il; i ++ ) {
 13789  
 13790  				this.skinIndices.push( skinIndices[ i ].clone() );
 13791  
 13792  			}
 13793  
 13794  			// line distances
 13795  
 13796  			var lineDistances = source.lineDistances;
 13797  
 13798  			for ( i = 0, il = lineDistances.length; i < il; i ++ ) {
 13799  
 13800  				this.lineDistances.push( lineDistances[ i ] );
 13801  
 13802  			}
 13803  
 13804  			// bounding box
 13805  
 13806  			var boundingBox = source.boundingBox;
 13807  
 13808  			if ( boundingBox !== null ) {
 13809  
 13810  				this.boundingBox = boundingBox.clone();
 13811  
 13812  			}
 13813  
 13814  			// bounding sphere
 13815  
 13816  			var boundingSphere = source.boundingSphere;
 13817  
 13818  			if ( boundingSphere !== null ) {
 13819  
 13820  				this.boundingSphere = boundingSphere.clone();
 13821  
 13822  			}
 13823  
 13824  			// update flags
 13825  
 13826  			this.elementsNeedUpdate = source.elementsNeedUpdate;
 13827  			this.verticesNeedUpdate = source.verticesNeedUpdate;
 13828  			this.uvsNeedUpdate = source.uvsNeedUpdate;
 13829  			this.normalsNeedUpdate = source.normalsNeedUpdate;
 13830  			this.colorsNeedUpdate = source.colorsNeedUpdate;
 13831  			this.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate;
 13832  			this.groupsNeedUpdate = source.groupsNeedUpdate;
 13833  
 13834  			return this;
 13835  
 13836  		},
 13837  
 13838  		dispose: function () {
 13839  
 13840  			this.dispatchEvent( { type: 'dispose' } );
 13841  
 13842  		}
 13843  
 13844  	};
 13845  
 13846  	Object.assign( Geometry.prototype, EventDispatcher.prototype );
 13847  
 13848  	/**
 13849  	 * @author alteredq / http://alteredqualia.com/
 13850  	 * @author mrdoob / http://mrdoob.com/
 13851  	 */
 13852  
 13853  	function BufferGeometry() {
 13854  
 13855  		Object.defineProperty( this, 'id', { value: GeometryIdCount() } );
 13856  
 13857  		this.uuid = _Math.generateUUID();
 13858  
 13859  		this.name = '';
 13860  		this.type = 'BufferGeometry';
 13861  
 13862  		this.index = null;
 13863  		this.attributes = {};
 13864  
 13865  		this.morphAttributes = {};
 13866  
 13867  		this.groups = [];
 13868  
 13869  		this.boundingBox = null;
 13870  		this.boundingSphere = null;
 13871  
 13872  		this.drawRange = { start: 0, count: Infinity };
 13873  
 13874  	}
 13875  
 13876  	BufferGeometry.prototype = {
 13877  
 13878  		constructor: BufferGeometry,
 13879  
 13880  		isBufferGeometry: true,
 13881  
 13882  		getIndex: function () {
 13883  
 13884  			return this.index;
 13885  
 13886  		},
 13887  
 13888  		setIndex: function ( index ) {
 13889  
 13890  			if ( Array.isArray( index ) ) {
 13891  
 13892  				this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
 13893  
 13894  			} else {
 13895  
 13896  				this.index = index;
 13897  
 13898  			}
 13899  
 13900  		},
 13901  
 13902  		addAttribute: function ( name, attribute ) {
 13903  
 13904  			if ( ( attribute && attribute.isBufferAttribute ) === false && ( attribute && attribute.isInterleavedBufferAttribute ) === false ) {
 13905  
 13906  				console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
 13907  
 13908  				this.addAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) );
 13909  
 13910  				return;
 13911  
 13912  			}
 13913  
 13914  			if ( name === 'index' ) {
 13915  
 13916  				console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' );
 13917  				this.setIndex( attribute );
 13918  
 13919  				return;
 13920  
 13921  			}
 13922  
 13923  			this.attributes[ name ] = attribute;
 13924  
 13925  			return this;
 13926  
 13927  		},
 13928  
 13929  		getAttribute: function ( name ) {
 13930  
 13931  			return this.attributes[ name ];
 13932  
 13933  		},
 13934  
 13935  		removeAttribute: function ( name ) {
 13936  
 13937  			delete this.attributes[ name ];
 13938  
 13939  			return this;
 13940  
 13941  		},
 13942  
 13943  		addGroup: function ( start, count, materialIndex ) {
 13944  
 13945  			this.groups.push( {
 13946  
 13947  				start: start,
 13948  				count: count,
 13949  				materialIndex: materialIndex !== undefined ? materialIndex : 0
 13950  
 13951  			} );
 13952  
 13953  		},
 13954  
 13955  		clearGroups: function () {
 13956  
 13957  			this.groups = [];
 13958  
 13959  		},
 13960  
 13961  		setDrawRange: function ( start, count ) {
 13962  
 13963  			this.drawRange.start = start;
 13964  			this.drawRange.count = count;
 13965  
 13966  		},
 13967  
 13968  		applyMatrix: function ( matrix ) {
 13969  
 13970  			var position = this.attributes.position;
 13971  
 13972  			if ( position !== undefined ) {
 13973  
 13974  				matrix.applyToBufferAttribute( position );
 13975  				position.needsUpdate = true;
 13976  
 13977  			}
 13978  
 13979  			var normal = this.attributes.normal;
 13980  
 13981  			if ( normal !== undefined ) {
 13982  
 13983  				var normalMatrix = new Matrix3().getNormalMatrix( matrix );
 13984  
 13985  				normalMatrix.applyToBufferAttribute( normal );
 13986  				normal.needsUpdate = true;
 13987  
 13988  			}
 13989  
 13990  			if ( this.boundingBox !== null ) {
 13991  
 13992  				this.computeBoundingBox();
 13993  
 13994  			}
 13995  
 13996  			if ( this.boundingSphere !== null ) {
 13997  
 13998  				this.computeBoundingSphere();
 13999  
 14000  			}
 14001  
 14002  			return this;
 14003  
 14004  		},
 14005  
 14006  		rotateX: function () {
 14007  
 14008  			// rotate geometry around world x-axis
 14009  
 14010  			var m1;
 14011  
 14012  			return function rotateX( angle ) {
 14013  
 14014  				if ( m1 === undefined ) m1 = new Matrix4();
 14015  
 14016  				m1.makeRotationX( angle );
 14017  
 14018  				this.applyMatrix( m1 );
 14019  
 14020  				return this;
 14021  
 14022  			};
 14023  
 14024  		}(),
 14025  
 14026  		rotateY: function () {
 14027  
 14028  			// rotate geometry around world y-axis
 14029  
 14030  			var m1;
 14031  
 14032  			return function rotateY( angle ) {
 14033  
 14034  				if ( m1 === undefined ) m1 = new Matrix4();
 14035  
 14036  				m1.makeRotationY( angle );
 14037  
 14038  				this.applyMatrix( m1 );
 14039  
 14040  				return this;
 14041  
 14042  			};
 14043  
 14044  		}(),
 14045  
 14046  		rotateZ: function () {
 14047  
 14048  			// rotate geometry around world z-axis
 14049  
 14050  			var m1;
 14051  
 14052  			return function rotateZ( angle ) {
 14053  
 14054  				if ( m1 === undefined ) m1 = new Matrix4();
 14055  
 14056  				m1.makeRotationZ( angle );
 14057  
 14058  				this.applyMatrix( m1 );
 14059  
 14060  				return this;
 14061  
 14062  			};
 14063  
 14064  		}(),
 14065  
 14066  		translate: function () {
 14067  
 14068  			// translate geometry
 14069  
 14070  			var m1;
 14071  
 14072  			return function translate( x, y, z ) {
 14073  
 14074  				if ( m1 === undefined ) m1 = new Matrix4();
 14075  
 14076  				m1.makeTranslation( x, y, z );
 14077  
 14078  				this.applyMatrix( m1 );
 14079  
 14080  				return this;
 14081  
 14082  			};
 14083  
 14084  		}(),
 14085  
 14086  		scale: function () {
 14087  
 14088  			// scale geometry
 14089  
 14090  			var m1;
 14091  
 14092  			return function scale( x, y, z ) {
 14093  
 14094  				if ( m1 === undefined ) m1 = new Matrix4();
 14095  
 14096  				m1.makeScale( x, y, z );
 14097  
 14098  				this.applyMatrix( m1 );
 14099  
 14100  				return this;
 14101  
 14102  			};
 14103  
 14104  		}(),
 14105  
 14106  		lookAt: function () {
 14107  
 14108  			var obj;
 14109  
 14110  			return function lookAt( vector ) {
 14111  
 14112  				if ( obj === undefined ) obj = new Object3D();
 14113  
 14114  				obj.lookAt( vector );
 14115  
 14116  				obj.updateMatrix();
 14117  
 14118  				this.applyMatrix( obj.matrix );
 14119  
 14120  			};
 14121  
 14122  		}(),
 14123  
 14124  		center: function () {
 14125  
 14126  			this.computeBoundingBox();
 14127  
 14128  			var offset = this.boundingBox.getCenter().negate();
 14129  
 14130  			this.translate( offset.x, offset.y, offset.z );
 14131  
 14132  			return offset;
 14133  
 14134  		},
 14135  
 14136  		setFromObject: function ( object ) {
 14137  
 14138  			// console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );
 14139  
 14140  			var geometry = object.geometry;
 14141  
 14142  			if ( object.isPoints || object.isLine ) {
 14143  
 14144  				var positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 );
 14145  				var colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 );
 14146  
 14147  				this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) );
 14148  				this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) );
 14149  
 14150  				if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) {
 14151  
 14152  					var lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 );
 14153  
 14154  					this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) );
 14155  
 14156  				}
 14157  
 14158  				if ( geometry.boundingSphere !== null ) {
 14159  
 14160  					this.boundingSphere = geometry.boundingSphere.clone();
 14161  
 14162  				}
 14163  
 14164  				if ( geometry.boundingBox !== null ) {
 14165  
 14166  					this.boundingBox = geometry.boundingBox.clone();
 14167  
 14168  				}
 14169  
 14170  			} else if ( object.isMesh ) {
 14171  
 14172  				if ( geometry && geometry.isGeometry ) {
 14173  
 14174  					this.fromGeometry( geometry );
 14175  
 14176  				}
 14177  
 14178  			}
 14179  
 14180  			return this;
 14181  
 14182  		},
 14183  
 14184  		updateFromObject: function ( object ) {
 14185  
 14186  			var geometry = object.geometry;
 14187  
 14188  			if ( object.isMesh ) {
 14189  
 14190  				var direct = geometry.__directGeometry;
 14191  
 14192  				if ( geometry.elementsNeedUpdate === true ) {
 14193  
 14194  					direct = undefined;
 14195  					geometry.elementsNeedUpdate = false;
 14196  
 14197  				}
 14198  
 14199  				if ( direct === undefined ) {
 14200  
 14201  					return this.fromGeometry( geometry );
 14202  
 14203  				}
 14204  
 14205  				direct.verticesNeedUpdate = geometry.verticesNeedUpdate;
 14206  				direct.normalsNeedUpdate = geometry.normalsNeedUpdate;
 14207  				direct.colorsNeedUpdate = geometry.colorsNeedUpdate;
 14208  				direct.uvsNeedUpdate = geometry.uvsNeedUpdate;
 14209  				direct.groupsNeedUpdate = geometry.groupsNeedUpdate;
 14210  
 14211  				geometry.verticesNeedUpdate = false;
 14212  				geometry.normalsNeedUpdate = false;
 14213  				geometry.colorsNeedUpdate = false;
 14214  				geometry.uvsNeedUpdate = false;
 14215  				geometry.groupsNeedUpdate = false;
 14216  
 14217  				geometry = direct;
 14218  
 14219  			}
 14220  
 14221  			var attribute;
 14222  
 14223  			if ( geometry.verticesNeedUpdate === true ) {
 14224  
 14225  				attribute = this.attributes.position;
 14226  
 14227  				if ( attribute !== undefined ) {
 14228  
 14229  					attribute.copyVector3sArray( geometry.vertices );
 14230  					attribute.needsUpdate = true;
 14231  
 14232  				}
 14233  
 14234  				geometry.verticesNeedUpdate = false;
 14235  
 14236  			}
 14237  
 14238  			if ( geometry.normalsNeedUpdate === true ) {
 14239  
 14240  				attribute = this.attributes.normal;
 14241  
 14242  				if ( attribute !== undefined ) {
 14243  
 14244  					attribute.copyVector3sArray( geometry.normals );
 14245  					attribute.needsUpdate = true;
 14246  
 14247  				}
 14248  
 14249  				geometry.normalsNeedUpdate = false;
 14250  
 14251  			}
 14252  
 14253  			if ( geometry.colorsNeedUpdate === true ) {
 14254  
 14255  				attribute = this.attributes.color;
 14256  
 14257  				if ( attribute !== undefined ) {
 14258  
 14259  					attribute.copyColorsArray( geometry.colors );
 14260  					attribute.needsUpdate = true;
 14261  
 14262  				}
 14263  
 14264  				geometry.colorsNeedUpdate = false;
 14265  
 14266  			}
 14267  
 14268  			if ( geometry.uvsNeedUpdate ) {
 14269  
 14270  				attribute = this.attributes.uv;
 14271  
 14272  				if ( attribute !== undefined ) {
 14273  
 14274  					attribute.copyVector2sArray( geometry.uvs );
 14275  					attribute.needsUpdate = true;
 14276  
 14277  				}
 14278  
 14279  				geometry.uvsNeedUpdate = false;
 14280  
 14281  			}
 14282  
 14283  			if ( geometry.lineDistancesNeedUpdate ) {
 14284  
 14285  				attribute = this.attributes.lineDistance;
 14286  
 14287  				if ( attribute !== undefined ) {
 14288  
 14289  					attribute.copyArray( geometry.lineDistances );
 14290  					attribute.needsUpdate = true;
 14291  
 14292  				}
 14293  
 14294  				geometry.lineDistancesNeedUpdate = false;
 14295  
 14296  			}
 14297  
 14298  			if ( geometry.groupsNeedUpdate ) {
 14299  
 14300  				geometry.computeGroups( object.geometry );
 14301  				this.groups = geometry.groups;
 14302  
 14303  				geometry.groupsNeedUpdate = false;
 14304  
 14305  			}
 14306  
 14307  			return this;
 14308  
 14309  		},
 14310  
 14311  		fromGeometry: function ( geometry ) {
 14312  
 14313  			geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry );
 14314  
 14315  			return this.fromDirectGeometry( geometry.__directGeometry );
 14316  
 14317  		},
 14318  
 14319  		fromDirectGeometry: function ( geometry ) {
 14320  
 14321  			var positions = new Float32Array( geometry.vertices.length * 3 );
 14322  			this.addAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
 14323  
 14324  			if ( geometry.normals.length > 0 ) {
 14325  
 14326  				var normals = new Float32Array( geometry.normals.length * 3 );
 14327  				this.addAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) );
 14328  
 14329  			}
 14330  
 14331  			if ( geometry.colors.length > 0 ) {
 14332  
 14333  				var colors = new Float32Array( geometry.colors.length * 3 );
 14334  				this.addAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) );
 14335  
 14336  			}
 14337  
 14338  			if ( geometry.uvs.length > 0 ) {
 14339  
 14340  				var uvs = new Float32Array( geometry.uvs.length * 2 );
 14341  				this.addAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) );
 14342  
 14343  			}
 14344  
 14345  			if ( geometry.uvs2.length > 0 ) {
 14346  
 14347  				var uvs2 = new Float32Array( geometry.uvs2.length * 2 );
 14348  				this.addAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) );
 14349  
 14350  			}
 14351  
 14352  			if ( geometry.indices.length > 0 ) {
 14353  
 14354  				var TypeArray = arrayMax( geometry.indices ) > 65535 ? Uint32Array : Uint16Array;
 14355  				var indices = new TypeArray( geometry.indices.length * 3 );
 14356  				this.setIndex( new BufferAttribute( indices, 1 ).copyIndicesArray( geometry.indices ) );
 14357  
 14358  			}
 14359  
 14360  			// groups
 14361  
 14362  			this.groups = geometry.groups;
 14363  
 14364  			// morphs
 14365  
 14366  			for ( var name in geometry.morphTargets ) {
 14367  
 14368  				var array = [];
 14369  				var morphTargets = geometry.morphTargets[ name ];
 14370  
 14371  				for ( var i = 0, l = morphTargets.length; i < l; i ++ ) {
 14372  
 14373  					var morphTarget = morphTargets[ i ];
 14374  
 14375  					var attribute = new Float32BufferAttribute( morphTarget.length * 3, 3 );
 14376  
 14377  					array.push( attribute.copyVector3sArray( morphTarget ) );
 14378  
 14379  				}
 14380  
 14381  				this.morphAttributes[ name ] = array;
 14382  
 14383  			}
 14384  
 14385  			// skinning
 14386  
 14387  			if ( geometry.skinIndices.length > 0 ) {
 14388  
 14389  				var skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 );
 14390  				this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) );
 14391  
 14392  			}
 14393  
 14394  			if ( geometry.skinWeights.length > 0 ) {
 14395  
 14396  				var skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 );
 14397  				this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) );
 14398  
 14399  			}
 14400  
 14401  			//
 14402  
 14403  			if ( geometry.boundingSphere !== null ) {
 14404  
 14405  				this.boundingSphere = geometry.boundingSphere.clone();
 14406  
 14407  			}
 14408  
 14409  			if ( geometry.boundingBox !== null ) {
 14410  
 14411  				this.boundingBox = geometry.boundingBox.clone();
 14412  
 14413  			}
 14414  
 14415  			return this;
 14416  
 14417  		},
 14418  
 14419  		computeBoundingBox: function () {
 14420  
 14421  			if ( this.boundingBox === null ) {
 14422  
 14423  				this.boundingBox = new Box3();
 14424  
 14425  			}
 14426  
 14427  			var position = this.attributes.position;
 14428  
 14429  			if ( position !== undefined ) {
 14430  
 14431  				this.boundingBox.setFromBufferAttribute( position );
 14432  
 14433  			} else {
 14434  
 14435  				this.boundingBox.makeEmpty();
 14436  
 14437  			}
 14438  
 14439  			if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
 14440  
 14441  				console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
 14442  
 14443  			}
 14444  
 14445  		},
 14446  
 14447  		computeBoundingSphere: function () {
 14448  
 14449  			var box = new Box3();
 14450  			var vector = new Vector3();
 14451  
 14452  			return function computeBoundingSphere() {
 14453  
 14454  				if ( this.boundingSphere === null ) {
 14455  
 14456  					this.boundingSphere = new Sphere();
 14457  
 14458  				}
 14459  
 14460  				var position = this.attributes.position;
 14461  
 14462  				if ( position ) {
 14463  
 14464  					var center = this.boundingSphere.center;
 14465  
 14466  					box.setFromBufferAttribute( position );
 14467  					box.getCenter( center );
 14468  
 14469  					// hoping to find a boundingSphere with a radius smaller than the
 14470  					// boundingSphere of the boundingBox: sqrt(3) smaller in the best case
 14471  
 14472  					var maxRadiusSq = 0;
 14473  
 14474  					for ( var i = 0, il = position.count; i < il; i ++ ) {
 14475  
 14476  						vector.x = position.getX( i );
 14477  						vector.y = position.getY( i );
 14478  						vector.z = position.getZ( i );
 14479  						maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
 14480  
 14481  					}
 14482  
 14483  					this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
 14484  
 14485  					if ( isNaN( this.boundingSphere.radius ) ) {
 14486  
 14487  						console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
 14488  
 14489  					}
 14490  
 14491  				}
 14492  
 14493  			};
 14494  
 14495  		}(),
 14496  
 14497  		computeFaceNormals: function () {
 14498  
 14499  			// backwards compatibility
 14500  
 14501  		},
 14502  
 14503  		computeVertexNormals: function () {
 14504  
 14505  			var index = this.index;
 14506  			var attributes = this.attributes;
 14507  			var groups = this.groups;
 14508  
 14509  			if ( attributes.position ) {
 14510  
 14511  				var positions = attributes.position.array;
 14512  
 14513  				if ( attributes.normal === undefined ) {
 14514  
 14515  					this.addAttribute( 'normal', new BufferAttribute( new Float32Array( positions.length ), 3 ) );
 14516  
 14517  				} else {
 14518  
 14519  					// reset existing normals to zero
 14520  
 14521  					var array = attributes.normal.array;
 14522  
 14523  					for ( var i = 0, il = array.length; i < il; i ++ ) {
 14524  
 14525  						array[ i ] = 0;
 14526  
 14527  					}
 14528  
 14529  				}
 14530  
 14531  				var normals = attributes.normal.array;
 14532  
 14533  				var vA, vB, vC;
 14534  				var pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
 14535  				var cb = new Vector3(), ab = new Vector3();
 14536  
 14537  				// indexed elements
 14538  
 14539  				if ( index ) {
 14540  
 14541  					var indices = index.array;
 14542  
 14543  					if ( groups.length === 0 ) {
 14544  
 14545  						this.addGroup( 0, indices.length );
 14546  
 14547  					}
 14548  
 14549  					for ( var j = 0, jl = groups.length; j < jl; ++ j ) {
 14550  
 14551  						var group = groups[ j ];
 14552  
 14553  						var start = group.start;
 14554  						var count = group.count;
 14555  
 14556  						for ( var i = start, il = start + count; i < il; i += 3 ) {
 14557  
 14558  							vA = indices[ i + 0 ] * 3;
 14559  							vB = indices[ i + 1 ] * 3;
 14560  							vC = indices[ i + 2 ] * 3;
 14561  
 14562  							pA.fromArray( positions, vA );
 14563  							pB.fromArray( positions, vB );
 14564  							pC.fromArray( positions, vC );
 14565  
 14566  							cb.subVectors( pC, pB );
 14567  							ab.subVectors( pA, pB );
 14568  							cb.cross( ab );
 14569  
 14570  							normals[ vA ] += cb.x;
 14571  							normals[ vA + 1 ] += cb.y;
 14572  							normals[ vA + 2 ] += cb.z;
 14573  
 14574  							normals[ vB ] += cb.x;
 14575  							normals[ vB + 1 ] += cb.y;
 14576  							normals[ vB + 2 ] += cb.z;
 14577  
 14578  							normals[ vC ] += cb.x;
 14579  							normals[ vC + 1 ] += cb.y;
 14580  							normals[ vC + 2 ] += cb.z;
 14581  
 14582  						}
 14583  
 14584  					}
 14585  
 14586  				} else {
 14587  
 14588  					// non-indexed elements (unconnected triangle soup)
 14589  
 14590  					for ( var i = 0, il = positions.length; i < il; i += 9 ) {
 14591  
 14592  						pA.fromArray( positions, i );
 14593  						pB.fromArray( positions, i + 3 );
 14594  						pC.fromArray( positions, i + 6 );
 14595  
 14596  						cb.subVectors( pC, pB );
 14597  						ab.subVectors( pA, pB );
 14598  						cb.cross( ab );
 14599  
 14600  						normals[ i ] = cb.x;
 14601  						normals[ i + 1 ] = cb.y;
 14602  						normals[ i + 2 ] = cb.z;
 14603  
 14604  						normals[ i + 3 ] = cb.x;
 14605  						normals[ i + 4 ] = cb.y;
 14606  						normals[ i + 5 ] = cb.z;
 14607  
 14608  						normals[ i + 6 ] = cb.x;
 14609  						normals[ i + 7 ] = cb.y;
 14610  						normals[ i + 8 ] = cb.z;
 14611  
 14612  					}
 14613  
 14614  				}
 14615  
 14616  				this.normalizeNormals();
 14617  
 14618  				attributes.normal.needsUpdate = true;
 14619  
 14620  			}
 14621  
 14622  		},
 14623  
 14624  		merge: function ( geometry, offset ) {
 14625  
 14626  			if ( ( geometry && geometry.isBufferGeometry ) === false ) {
 14627  
 14628  				console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
 14629  				return;
 14630  
 14631  			}
 14632  
 14633  			if ( offset === undefined ) offset = 0;
 14634  
 14635  			var attributes = this.attributes;
 14636  
 14637  			for ( var key in attributes ) {
 14638  
 14639  				if ( geometry.attributes[ key ] === undefined ) continue;
 14640  
 14641  				var attribute1 = attributes[ key ];
 14642  				var attributeArray1 = attribute1.array;
 14643  
 14644  				var attribute2 = geometry.attributes[ key ];
 14645  				var attributeArray2 = attribute2.array;
 14646  
 14647  				var attributeSize = attribute2.itemSize;
 14648  
 14649  				for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) {
 14650  
 14651  					attributeArray1[ j ] = attributeArray2[ i ];
 14652  
 14653  				}
 14654  
 14655  			}
 14656  
 14657  			return this;
 14658  
 14659  		},
 14660  
 14661  		normalizeNormals: function () {
 14662  
 14663  			var normals = this.attributes.normal.array;
 14664  
 14665  			var x, y, z, n;
 14666  
 14667  			for ( var i = 0, il = normals.length; i < il; i += 3 ) {
 14668  
 14669  				x = normals[ i ];
 14670  				y = normals[ i + 1 ];
 14671  				z = normals[ i + 2 ];
 14672  
 14673  				n = 1.0 / Math.sqrt( x * x + y * y + z * z );
 14674  
 14675  				normals[ i ] *= n;
 14676  				normals[ i + 1 ] *= n;
 14677  				normals[ i + 2 ] *= n;
 14678  
 14679  			}
 14680  
 14681  		},
 14682  
 14683  		toNonIndexed: function () {
 14684  
 14685  			if ( this.index === null ) {
 14686  
 14687  				console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' );
 14688  				return this;
 14689  
 14690  			}
 14691  
 14692  			var geometry2 = new BufferGeometry();
 14693  
 14694  			var indices = this.index.array;
 14695  			var attributes = this.attributes;
 14696  
 14697  			for ( var name in attributes ) {
 14698  
 14699  				var attribute = attributes[ name ];
 14700  
 14701  				var array = attribute.array;
 14702  				var itemSize = attribute.itemSize;
 14703  
 14704  				var array2 = new array.constructor( indices.length * itemSize );
 14705  
 14706  				var index = 0, index2 = 0;
 14707  
 14708  				for ( var i = 0, l = indices.length; i < l; i ++ ) {
 14709  
 14710  					index = indices[ i ] * itemSize;
 14711  
 14712  					for ( var j = 0; j < itemSize; j ++ ) {
 14713  
 14714  						array2[ index2 ++ ] = array[ index ++ ];
 14715  
 14716  					}
 14717  
 14718  				}
 14719  
 14720  				geometry2.addAttribute( name, new BufferAttribute( array2, itemSize ) );
 14721  
 14722  			}
 14723  
 14724  			return geometry2;
 14725  
 14726  		},
 14727  
 14728  		toJSON: function () {
 14729  
 14730  			var data = {
 14731  				metadata: {
 14732  					version: 4.4,
 14733  					type: 'BufferGeometry',
 14734  					generator: 'BufferGeometry.toJSON'
 14735  				}
 14736  			};
 14737  
 14738  			// standard BufferGeometry serialization
 14739  
 14740  			data.uuid = this.uuid;
 14741  			data.type = this.type;
 14742  			if ( this.name !== '' ) data.name = this.name;
 14743  
 14744  			if ( this.parameters !== undefined ) {
 14745  
 14746  				var parameters = this.parameters;
 14747  
 14748  				for ( var key in parameters ) {
 14749  
 14750  					if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
 14751  
 14752  				}
 14753  
 14754  				return data;
 14755  
 14756  			}
 14757  
 14758  			data.data = { attributes: {} };
 14759  
 14760  			var index = this.index;
 14761  
 14762  			if ( index !== null ) {
 14763  
 14764  				var array = Array.prototype.slice.call( index.array );
 14765  
 14766  				data.data.index = {
 14767  					type: index.array.constructor.name,
 14768  					array: array
 14769  				};
 14770  
 14771  			}
 14772  
 14773  			var attributes = this.attributes;
 14774  
 14775  			for ( var key in attributes ) {
 14776  
 14777  				var attribute = attributes[ key ];
 14778  
 14779  				var array = Array.prototype.slice.call( attribute.array );
 14780  
 14781  				data.data.attributes[ key ] = {
 14782  					itemSize: attribute.itemSize,
 14783  					type: attribute.array.constructor.name,
 14784  					array: array,
 14785  					normalized: attribute.normalized
 14786  				};
 14787  
 14788  			}
 14789  
 14790  			var groups = this.groups;
 14791  
 14792  			if ( groups.length > 0 ) {
 14793  
 14794  				data.data.groups = JSON.parse( JSON.stringify( groups ) );
 14795  
 14796  			}
 14797  
 14798  			var boundingSphere = this.boundingSphere;
 14799  
 14800  			if ( boundingSphere !== null ) {
 14801  
 14802  				data.data.boundingSphere = {
 14803  					center: boundingSphere.center.toArray(),
 14804  					radius: boundingSphere.radius
 14805  				};
 14806  
 14807  			}
 14808  
 14809  			return data;
 14810  
 14811  		},
 14812  
 14813  		clone: function () {
 14814  
 14815  			/*
 14816  			// Handle primitives
 14817  
 14818  			var parameters = this.parameters;
 14819  
 14820  			if ( parameters !== undefined ) {
 14821  
 14822  				var values = [];
 14823  
 14824  				for ( var key in parameters ) {
 14825  
 14826  					values.push( parameters[ key ] );
 14827  
 14828  				}
 14829  
 14830  				var geometry = Object.create( this.constructor.prototype );
 14831  				this.constructor.apply( geometry, values );
 14832  				return geometry;
 14833  
 14834  			}
 14835  
 14836  			return new this.constructor().copy( this );
 14837  			*/
 14838  
 14839  			return new BufferGeometry().copy( this );
 14840  
 14841  		},
 14842  
 14843  		copy: function ( source ) {
 14844  
 14845  			var name, i, l;
 14846  
 14847  			// reset
 14848  
 14849  			this.index = null;
 14850  			this.attributes = {};
 14851  			this.morphAttributes = {};
 14852  			this.groups = [];
 14853  			this.boundingBox = null;
 14854  			this.boundingSphere = null;
 14855  
 14856  			// name
 14857  
 14858  			this.name = source.name;
 14859  
 14860  			// index
 14861  
 14862  			var index = source.index;
 14863  
 14864  			if ( index !== null ) {
 14865  
 14866  				this.setIndex( index.clone() );
 14867  
 14868  			}
 14869  
 14870  			// attributes
 14871  
 14872  			var attributes = source.attributes;
 14873  
 14874  			for ( name in attributes ) {
 14875  
 14876  				var attribute = attributes[ name ];
 14877  				this.addAttribute( name, attribute.clone() );
 14878  
 14879  			}
 14880  
 14881  			// morph attributes
 14882  
 14883  			var morphAttributes = source.morphAttributes;
 14884  
 14885  			for ( name in morphAttributes ) {
 14886  
 14887  				var array = [];
 14888  				var morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
 14889  
 14890  				for ( i = 0, l = morphAttribute.length; i < l; i ++ ) {
 14891  
 14892  					array.push( morphAttribute[ i ].clone() );
 14893  
 14894  				}
 14895  
 14896  				this.morphAttributes[ name ] = array;
 14897  
 14898  			}
 14899  
 14900  			// groups
 14901  
 14902  			var groups = source.groups;
 14903  
 14904  			for ( i = 0, l = groups.length; i < l; i ++ ) {
 14905  
 14906  				var group = groups[ i ];
 14907  				this.addGroup( group.start, group.count, group.materialIndex );
 14908  
 14909  			}
 14910  
 14911  			// bounding box
 14912  
 14913  			var boundingBox = source.boundingBox;
 14914  
 14915  			if ( boundingBox !== null ) {
 14916  
 14917  				this.boundingBox = boundingBox.clone();
 14918  
 14919  			}
 14920  
 14921  			// bounding sphere
 14922  
 14923  			var boundingSphere = source.boundingSphere;
 14924  
 14925  			if ( boundingSphere !== null ) {
 14926  
 14927  				this.boundingSphere = boundingSphere.clone();
 14928  
 14929  			}
 14930  
 14931  			// draw range
 14932  
 14933  			this.drawRange.start = source.drawRange.start;
 14934  			this.drawRange.count = source.drawRange.count;
 14935  
 14936  			return this;
 14937  
 14938  		},
 14939  
 14940  		dispose: function () {
 14941  
 14942  			this.dispatchEvent( { type: 'dispose' } );
 14943  
 14944  		}
 14945  
 14946  	};
 14947  
 14948  	BufferGeometry.MaxIndex = 65535;
 14949  
 14950  	Object.assign( BufferGeometry.prototype, EventDispatcher.prototype );
 14951  
 14952  	/**
 14953  	 * @author mrdoob / http://mrdoob.com/
 14954  	 * @author alteredq / http://alteredqualia.com/
 14955  	 * @author mikael emtinger / http://gomo.se/
 14956  	 * @author jonobr1 / http://jonobr1.com/
 14957  	 */
 14958  
 14959  	function Mesh( geometry, material ) {
 14960  
 14961  		Object3D.call( this );
 14962  
 14963  		this.type = 'Mesh';
 14964  
 14965  		this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
 14966  		this.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } );
 14967  
 14968  		this.drawMode = TrianglesDrawMode;
 14969  
 14970  		this.updateMorphTargets();
 14971  
 14972  	}
 14973  
 14974  	Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), {
 14975  
 14976  		constructor: Mesh,
 14977  
 14978  		isMesh: true,
 14979  
 14980  		setDrawMode: function ( value ) {
 14981  
 14982  			this.drawMode = value;
 14983  
 14984  		},
 14985  
 14986  		copy: function ( source ) {
 14987  
 14988  			Object3D.prototype.copy.call( this, source );
 14989  
 14990  			this.drawMode = source.drawMode;
 14991  
 14992  			return this;
 14993  
 14994  		},
 14995  
 14996  		updateMorphTargets: function () {
 14997  
 14998  			var morphTargets = this.geometry.morphTargets;
 14999  
 15000  			if ( morphTargets !== undefined && morphTargets.length > 0 ) {
 15001  
 15002  				this.morphTargetInfluences = [];
 15003  				this.morphTargetDictionary = {};
 15004  
 15005  				for ( var m = 0, ml = morphTargets.length; m < ml; m ++ ) {
 15006  
 15007  					this.morphTargetInfluences.push( 0 );
 15008  					this.morphTargetDictionary[ morphTargets[ m ].name ] = m;
 15009  
 15010  				}
 15011  
 15012  			}
 15013  
 15014  		},
 15015  
 15016  		raycast: ( function () {
 15017  
 15018  			var inverseMatrix = new Matrix4();
 15019  			var ray = new Ray();
 15020  			var sphere = new Sphere();
 15021  
 15022  			var vA = new Vector3();
 15023  			var vB = new Vector3();
 15024  			var vC = new Vector3();
 15025  
 15026  			var tempA = new Vector3();
 15027  			var tempB = new Vector3();
 15028  			var tempC = new Vector3();
 15029  
 15030  			var uvA = new Vector2();
 15031  			var uvB = new Vector2();
 15032  			var uvC = new Vector2();
 15033  
 15034  			var barycoord = new Vector3();
 15035  
 15036  			var intersectionPoint = new Vector3();
 15037  			var intersectionPointWorld = new Vector3();
 15038  
 15039  			function uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) {
 15040  
 15041  				Triangle.barycoordFromPoint( point, p1, p2, p3, barycoord );
 15042  
 15043  				uv1.multiplyScalar( barycoord.x );
 15044  				uv2.multiplyScalar( barycoord.y );
 15045  				uv3.multiplyScalar( barycoord.z );
 15046  
 15047  				uv1.add( uv2 ).add( uv3 );
 15048  
 15049  				return uv1.clone();
 15050  
 15051  			}
 15052  
 15053  			function checkIntersection( object, raycaster, ray, pA, pB, pC, point ) {
 15054  
 15055  				var intersect;
 15056  				var material = object.material;
 15057  
 15058  				if ( material.side === BackSide ) {
 15059  
 15060  					intersect = ray.intersectTriangle( pC, pB, pA, true, point );
 15061  
 15062  				} else {
 15063  
 15064  					intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );
 15065  
 15066  				}
 15067  
 15068  				if ( intersect === null ) return null;
 15069  
 15070  				intersectionPointWorld.copy( point );
 15071  				intersectionPointWorld.applyMatrix4( object.matrixWorld );
 15072  
 15073  				var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld );
 15074  
 15075  				if ( distance < raycaster.near || distance > raycaster.far ) return null;
 15076  
 15077  				return {
 15078  					distance: distance,
 15079  					point: intersectionPointWorld.clone(),
 15080  					object: object
 15081  				};
 15082  
 15083  			}
 15084  
 15085  			function checkBufferGeometryIntersection( object, raycaster, ray, position, uv, a, b, c ) {
 15086  
 15087  				vA.fromBufferAttribute( position, a );
 15088  				vB.fromBufferAttribute( position, b );
 15089  				vC.fromBufferAttribute( position, c );
 15090  
 15091  				var intersection = checkIntersection( object, raycaster, ray, vA, vB, vC, intersectionPoint );
 15092  
 15093  				if ( intersection ) {
 15094  
 15095  					if ( uv ) {
 15096  
 15097  						uvA.fromBufferAttribute( uv, a );
 15098  						uvB.fromBufferAttribute( uv, b );
 15099  						uvC.fromBufferAttribute( uv, c );
 15100  
 15101  						intersection.uv = uvIntersection( intersectionPoint,  vA, vB, vC, uvA, uvB, uvC );
 15102  
 15103  					}
 15104  
 15105  					intersection.face = new Face3( a, b, c, Triangle.normal( vA, vB, vC ) );
 15106  					intersection.faceIndex = a;
 15107  
 15108  				}
 15109  
 15110  				return intersection;
 15111  
 15112  			}
 15113  
 15114  			return function raycast( raycaster, intersects ) {
 15115  
 15116  				var geometry = this.geometry;
 15117  				var material = this.material;
 15118  				var matrixWorld = this.matrixWorld;
 15119  
 15120  				if ( material === undefined ) return;
 15121  
 15122  				// Checking boundingSphere distance to ray
 15123  
 15124  				if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
 15125  
 15126  				sphere.copy( geometry.boundingSphere );
 15127  				sphere.applyMatrix4( matrixWorld );
 15128  
 15129  				if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
 15130  
 15131  				//
 15132  
 15133  				inverseMatrix.getInverse( matrixWorld );
 15134  				ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
 15135  
 15136  				// Check boundingBox before continuing
 15137  
 15138  				if ( geometry.boundingBox !== null ) {
 15139  
 15140  					if ( ray.intersectsBox( geometry.boundingBox ) === false ) return;
 15141  
 15142  				}
 15143  
 15144  				var intersection;
 15145  
 15146  				if ( geometry.isBufferGeometry ) {
 15147  
 15148  					var a, b, c;
 15149  					var index = geometry.index;
 15150  					var position = geometry.attributes.position;
 15151  					var uv = geometry.attributes.uv;
 15152  					var i, l;
 15153  
 15154  					if ( index !== null ) {
 15155  
 15156  						// indexed buffer geometry
 15157  
 15158  						for ( i = 0, l = index.count; i < l; i += 3 ) {
 15159  
 15160  							a = index.getX( i );
 15161  							b = index.getX( i + 1 );
 15162  							c = index.getX( i + 2 );
 15163  
 15164  							intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );
 15165  
 15166  							if ( intersection ) {
 15167  
 15168  								intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indices buffer semantics
 15169  								intersects.push( intersection );
 15170  
 15171  							}
 15172  
 15173  						}
 15174  
 15175  					} else {
 15176  
 15177  						// non-indexed buffer geometry
 15178  
 15179  						for ( i = 0, l = position.count; i < l; i += 3 ) {
 15180  
 15181  							a = i;
 15182  							b = i + 1;
 15183  							c = i + 2;
 15184  
 15185  							intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );
 15186  
 15187  							if ( intersection ) {
 15188  
 15189  								intersection.index = a; // triangle number in positions buffer semantics
 15190  								intersects.push( intersection );
 15191  
 15192  							}
 15193  
 15194  						}
 15195  
 15196  					}
 15197  
 15198  				} else if ( geometry.isGeometry ) {
 15199  
 15200  					var fvA, fvB, fvC;
 15201  					var isFaceMaterial = ( material && material.isMultiMaterial );
 15202  					var materials = isFaceMaterial === true ? material.materials : null;
 15203  
 15204  					var vertices = geometry.vertices;
 15205  					var faces = geometry.faces;
 15206  					var uvs;
 15207  
 15208  					var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
 15209  					if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs;
 15210  
 15211  					for ( var f = 0, fl = faces.length; f < fl; f ++ ) {
 15212  
 15213  						var face = faces[ f ];
 15214  						var faceMaterial = isFaceMaterial === true ? materials[ face.materialIndex ] : material;
 15215  
 15216  						if ( faceMaterial === undefined ) continue;
 15217  
 15218  						fvA = vertices[ face.a ];
 15219  						fvB = vertices[ face.b ];
 15220  						fvC = vertices[ face.c ];
 15221  
 15222  						if ( faceMaterial.morphTargets === true ) {
 15223  
 15224  							var morphTargets = geometry.morphTargets;
 15225  							var morphInfluences = this.morphTargetInfluences;
 15226  
 15227  							vA.set( 0, 0, 0 );
 15228  							vB.set( 0, 0, 0 );
 15229  							vC.set( 0, 0, 0 );
 15230  
 15231  							for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
 15232  
 15233  								var influence = morphInfluences[ t ];
 15234  
 15235  								if ( influence === 0 ) continue;
 15236  
 15237  								var targets = morphTargets[ t ].vertices;
 15238  
 15239  								vA.addScaledVector( tempA.subVectors( targets[ face.a ], fvA ), influence );
 15240  								vB.addScaledVector( tempB.subVectors( targets[ face.b ], fvB ), influence );
 15241  								vC.addScaledVector( tempC.subVectors( targets[ face.c ], fvC ), influence );
 15242  
 15243  							}
 15244  
 15245  							vA.add( fvA );
 15246  							vB.add( fvB );
 15247  							vC.add( fvC );
 15248  
 15249  							fvA = vA;
 15250  							fvB = vB;
 15251  							fvC = vC;
 15252  
 15253  						}
 15254  
 15255  						intersection = checkIntersection( this, raycaster, ray, fvA, fvB, fvC, intersectionPoint );
 15256  
 15257  						if ( intersection ) {
 15258  
 15259  							if ( uvs ) {
 15260  
 15261  								var uvs_f = uvs[ f ];
 15262  								uvA.copy( uvs_f[ 0 ] );
 15263  								uvB.copy( uvs_f[ 1 ] );
 15264  								uvC.copy( uvs_f[ 2 ] );
 15265  
 15266  								intersection.uv = uvIntersection( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC );
 15267  
 15268  							}
 15269  
 15270  							intersection.face = face;
 15271  							intersection.faceIndex = f;
 15272  							intersects.push( intersection );
 15273  
 15274  						}
 15275  
 15276  					}
 15277  
 15278  				}
 15279  
 15280  			};
 15281  
 15282  		}() ),
 15283  
 15284  		clone: function () {
 15285  
 15286  			return new this.constructor( this.geometry, this.material ).copy( this );
 15287  
 15288  		}
 15289  
 15290  	} );
 15291  
 15292  	/**
 15293  	 * @author mrdoob / http://mrdoob.com/
 15294  	 * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as
 15295  	 */
 15296  
 15297  	function BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {
 15298  
 15299  		Geometry.call( this );
 15300  
 15301  		this.type = 'BoxGeometry';
 15302  
 15303  		this.parameters = {
 15304  			width: width,
 15305  			height: height,
 15306  			depth: depth,
 15307  			widthSegments: widthSegments,
 15308  			heightSegments: heightSegments,
 15309  			depthSegments: depthSegments
 15310  		};
 15311  
 15312  		this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) );
 15313  		this.mergeVertices();
 15314  
 15315  	}
 15316  
 15317  	BoxGeometry.prototype = Object.create( Geometry.prototype );
 15318  	BoxGeometry.prototype.constructor = BoxGeometry;
 15319  
 15320  	/**
 15321  	 * @author Mugen87 / https://github.com/Mugen87
 15322  	 */
 15323  
 15324  	function BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {
 15325  
 15326  		BufferGeometry.call( this );
 15327  
 15328  		this.type = 'BoxBufferGeometry';
 15329  
 15330  		this.parameters = {
 15331  			width: width,
 15332  			height: height,
 15333  			depth: depth,
 15334  			widthSegments: widthSegments,
 15335  			heightSegments: heightSegments,
 15336  			depthSegments: depthSegments
 15337  		};
 15338  
 15339  		var scope = this;
 15340  
 15341  		// segments
 15342  
 15343  		widthSegments = Math.floor( widthSegments ) || 1;
 15344  		heightSegments = Math.floor( heightSegments ) || 1;
 15345  		depthSegments = Math.floor( depthSegments ) || 1;
 15346  
 15347  		// buffers
 15348  
 15349  		var indices = [];
 15350  		var vertices = [];
 15351  		var normals = [];
 15352  		var uvs = [];
 15353  
 15354  		// helper variables
 15355  
 15356  		var numberOfVertices = 0;
 15357  		var groupStart = 0;
 15358  
 15359  		// build each side of the box geometry
 15360  
 15361  		buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height,   width,  depthSegments, heightSegments, 0 ); // px
 15362  		buildPlane( 'z', 'y', 'x',   1, - 1, depth, height, - width,  depthSegments, heightSegments, 1 ); // nx
 15363  		buildPlane( 'x', 'z', 'y',   1,   1, width, depth,    height, widthSegments, depthSegments,  2 ); // py
 15364  		buildPlane( 'x', 'z', 'y',   1, - 1, width, depth,  - height, widthSegments, depthSegments,  3 ); // ny
 15365  		buildPlane( 'x', 'y', 'z',   1, - 1, width, height,   depth,  widthSegments, heightSegments, 4 ); // pz
 15366  		buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth,  widthSegments, heightSegments, 5 ); // nz
 15367  
 15368  		// build geometry
 15369  
 15370  		this.setIndex( indices );
 15371  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 15372  		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
 15373  		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 15374  
 15375  		function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
 15376  
 15377  			var segmentWidth = width / gridX;
 15378  			var segmentHeight = height / gridY;
 15379  
 15380  			var widthHalf = width / 2;
 15381  			var heightHalf = height / 2;
 15382  			var depthHalf = depth / 2;
 15383  
 15384  			var gridX1 = gridX + 1;
 15385  			var gridY1 = gridY + 1;
 15386  
 15387  			var vertexCounter = 0;
 15388  			var groupCount = 0;
 15389  
 15390  			var ix, iy;
 15391  
 15392  			var vector = new Vector3();
 15393  
 15394  			// generate vertices, normals and uvs
 15395  
 15396  			for ( iy = 0; iy < gridY1; iy ++ ) {
 15397  
 15398  				var y = iy * segmentHeight - heightHalf;
 15399  
 15400  				for ( ix = 0; ix < gridX1; ix ++ ) {
 15401  
 15402  					var x = ix * segmentWidth - widthHalf;
 15403  
 15404  					// set values to correct vector component
 15405  
 15406  					vector[ u ] = x * udir;
 15407  					vector[ v ] = y * vdir;
 15408  					vector[ w ] = depthHalf;
 15409  
 15410  					// now apply vector to vertex buffer
 15411  
 15412  					vertices.push( vector.x, vector.y, vector.z );
 15413  
 15414  					// set values to correct vector component
 15415  
 15416  					vector[ u ] = 0;
 15417  					vector[ v ] = 0;
 15418  					vector[ w ] = depth > 0 ? 1 : - 1;
 15419  
 15420  					// now apply vector to normal buffer
 15421  
 15422  					normals.push( vector.x, vector.y, vector.z );
 15423  
 15424  					// uvs
 15425  
 15426  					uvs.push( ix / gridX );
 15427  					uvs.push( 1 - ( iy / gridY ) );
 15428  
 15429  					// counters
 15430  
 15431  					vertexCounter += 1;
 15432  
 15433  				}
 15434  
 15435  			}
 15436  
 15437  			// indices
 15438  
 15439  			// 1. you need three indices to draw a single face
 15440  			// 2. a single segment consists of two faces
 15441  			// 3. so we need to generate six (2*3) indices per segment
 15442  
 15443  			for ( iy = 0; iy < gridY; iy ++ ) {
 15444  
 15445  				for ( ix = 0; ix < gridX; ix ++ ) {
 15446  
 15447  					var a = numberOfVertices + ix + gridX1 * iy;
 15448  					var b = numberOfVertices + ix + gridX1 * ( iy + 1 );
 15449  					var c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
 15450  					var d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
 15451  
 15452  					// faces
 15453  
 15454  					indices.push( a, b, d );
 15455  					indices.push( b, c, d );
 15456  
 15457  					// increase counter
 15458  
 15459  					groupCount += 6;
 15460  
 15461  				}
 15462  
 15463  			}
 15464  
 15465  			// add a group to the geometry. this will ensure multi material support
 15466  
 15467  			scope.addGroup( groupStart, groupCount, materialIndex );
 15468  
 15469  			// calculate new start value for groups
 15470  
 15471  			groupStart += groupCount;
 15472  
 15473  			// update total number of vertices
 15474  
 15475  			numberOfVertices += vertexCounter;
 15476  
 15477  		}
 15478  
 15479  	}
 15480  
 15481  	BoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 15482  	BoxBufferGeometry.prototype.constructor = BoxBufferGeometry;
 15483  
 15484  	/**
 15485  	 * @author mrdoob / http://mrdoob.com/
 15486  	 * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as
 15487  	 */
 15488  
 15489  	function PlaneGeometry( width, height, widthSegments, heightSegments ) {
 15490  
 15491  		Geometry.call( this );
 15492  
 15493  		this.type = 'PlaneGeometry';
 15494  
 15495  		this.parameters = {
 15496  			width: width,
 15497  			height: height,
 15498  			widthSegments: widthSegments,
 15499  			heightSegments: heightSegments
 15500  		};
 15501  
 15502  		this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) );
 15503  
 15504  	}
 15505  
 15506  	PlaneGeometry.prototype = Object.create( Geometry.prototype );
 15507  	PlaneGeometry.prototype.constructor = PlaneGeometry;
 15508  
 15509  	/**
 15510  	 * @author mrdoob / http://mrdoob.com/
 15511  	 * @author Mugen87 / https://github.com/Mugen87
 15512  	 *
 15513  	 * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as
 15514  	 */
 15515  
 15516  	function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) {
 15517  
 15518  		BufferGeometry.call( this );
 15519  
 15520  		this.type = 'PlaneBufferGeometry';
 15521  
 15522  		this.parameters = {
 15523  			width: width,
 15524  			height: height,
 15525  			widthSegments: widthSegments,
 15526  			heightSegments: heightSegments
 15527  		};
 15528  
 15529  		var width_half = width / 2;
 15530  		var height_half = height / 2;
 15531  
 15532  		var gridX = Math.floor( widthSegments ) || 1;
 15533  		var gridY = Math.floor( heightSegments ) || 1;
 15534  
 15535  		var gridX1 = gridX + 1;
 15536  		var gridY1 = gridY + 1;
 15537  
 15538  		var segment_width = width / gridX;
 15539  		var segment_height = height / gridY;
 15540  
 15541  		var ix, iy;
 15542  
 15543  		// buffers
 15544  
 15545  		var indices = [];
 15546  		var vertices = [];
 15547  		var normals = [];
 15548  		var uvs = [];
 15549  
 15550  		// generate vertices, normals and uvs
 15551  
 15552  		for ( iy = 0; iy < gridY1; iy ++ ) {
 15553  
 15554  			var y = iy * segment_height - height_half;
 15555  
 15556  			for ( ix = 0; ix < gridX1; ix ++ ) {
 15557  
 15558  				var x = ix * segment_width - width_half;
 15559  
 15560  				vertices.push( x, - y, 0 );
 15561  
 15562  				normals.push( 0, 0, 1 );
 15563  
 15564  				uvs.push( ix / gridX );
 15565  				uvs.push( 1 - ( iy / gridY ) );
 15566  
 15567  			}
 15568  
 15569  		}
 15570  
 15571  		// indices
 15572  
 15573  		for ( iy = 0; iy < gridY; iy ++ ) {
 15574  
 15575  			for ( ix = 0; ix < gridX; ix ++ ) {
 15576  
 15577  				var a = ix + gridX1 * iy;
 15578  				var b = ix + gridX1 * ( iy + 1 );
 15579  				var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
 15580  				var d = ( ix + 1 ) + gridX1 * iy;
 15581  
 15582  				// faces
 15583  
 15584  				indices.push( a, b, d );
 15585  				indices.push( b, c, d );
 15586  
 15587  			}
 15588  
 15589  		}
 15590  
 15591  		// build geometry
 15592  
 15593  		this.setIndex( indices );
 15594  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 15595  		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
 15596  		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 15597  
 15598  	}
 15599  
 15600  	PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 15601  	PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry;
 15602  
 15603  	/**
 15604  	 * @author mrdoob / http://mrdoob.com/
 15605  	 * @author mikael emtinger / http://gomo.se/
 15606  	 * @author WestLangley / http://github.com/WestLangley
 15607  	*/
 15608  
 15609  	function Camera() {
 15610  
 15611  		Object3D.call( this );
 15612  
 15613  		this.type = 'Camera';
 15614  
 15615  		this.matrixWorldInverse = new Matrix4();
 15616  		this.projectionMatrix = new Matrix4();
 15617  
 15618  	}
 15619  
 15620  	Camera.prototype = Object.create( Object3D.prototype );
 15621  	Camera.prototype.constructor = Camera;
 15622  
 15623  	Camera.prototype.isCamera = true;
 15624  
 15625  	Camera.prototype.getWorldDirection = function () {
 15626  
 15627  		var quaternion = new Quaternion();
 15628  
 15629  		return function getWorldDirection( optionalTarget ) {
 15630  
 15631  			var result = optionalTarget || new Vector3();
 15632  
 15633  			this.getWorldQuaternion( quaternion );
 15634  
 15635  			return result.set( 0, 0, - 1 ).applyQuaternion( quaternion );
 15636  
 15637  		};
 15638  
 15639  	}();
 15640  
 15641  	Camera.prototype.lookAt = function () {
 15642  
 15643  		// This routine does not support cameras with rotated and/or translated parent(s)
 15644  
 15645  		var m1 = new Matrix4();
 15646  
 15647  		return function lookAt( vector ) {
 15648  
 15649  			m1.lookAt( this.position, vector, this.up );
 15650  
 15651  			this.quaternion.setFromRotationMatrix( m1 );
 15652  
 15653  		};
 15654  
 15655  	}();
 15656  
 15657  	Camera.prototype.clone = function () {
 15658  
 15659  		return new this.constructor().copy( this );
 15660  
 15661  	};
 15662  
 15663  	Camera.prototype.copy = function ( source ) {
 15664  
 15665  		Object3D.prototype.copy.call( this, source );
 15666  
 15667  		this.matrixWorldInverse.copy( source.matrixWorldInverse );
 15668  		this.projectionMatrix.copy( source.projectionMatrix );
 15669  
 15670  		return this;
 15671  
 15672  	};
 15673  
 15674  	/**
 15675  	 * @author mrdoob / http://mrdoob.com/
 15676  	 * @author greggman / http://games.greggman.com/
 15677  	 * @author zz85 / http://www.lab4games.net/zz85/blog
 15678  	 * @author tschw
 15679  	 */
 15680  
 15681  	function PerspectiveCamera( fov, aspect, near, far ) {
 15682  
 15683  		Camera.call( this );
 15684  
 15685  		this.type = 'PerspectiveCamera';
 15686  
 15687  		this.fov = fov !== undefined ? fov : 50;
 15688  		this.zoom = 1;
 15689  
 15690  		this.near = near !== undefined ? near : 0.1;
 15691  		this.far = far !== undefined ? far : 2000;
 15692  		this.focus = 10;
 15693  
 15694  		this.aspect = aspect !== undefined ? aspect : 1;
 15695  		this.view = null;
 15696  
 15697  		this.filmGauge = 35;	// width of the film (default in millimeters)
 15698  		this.filmOffset = 0;	// horizontal film offset (same unit as gauge)
 15699  
 15700  		this.updateProjectionMatrix();
 15701  
 15702  	}
 15703  
 15704  	PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
 15705  
 15706  		constructor: PerspectiveCamera,
 15707  
 15708  		isPerspectiveCamera: true,
 15709  
 15710  		copy: function ( source ) {
 15711  
 15712  			Camera.prototype.copy.call( this, source );
 15713  
 15714  			this.fov = source.fov;
 15715  			this.zoom = source.zoom;
 15716  
 15717  			this.near = source.near;
 15718  			this.far = source.far;
 15719  			this.focus = source.focus;
 15720  
 15721  			this.aspect = source.aspect;
 15722  			this.view = source.view === null ? null : Object.assign( {}, source.view );
 15723  
 15724  			this.filmGauge = source.filmGauge;
 15725  			this.filmOffset = source.filmOffset;
 15726  
 15727  			return this;
 15728  
 15729  		},
 15730  
 15731  		/**
 15732  		 * Sets the FOV by focal length in respect to the current .filmGauge.
 15733  		 *
 15734  		 * The default film gauge is 35, so that the focal length can be specified for
 15735  		 * a 35mm (full frame) camera.
 15736  		 *
 15737  		 * Values for focal length and film gauge must have the same unit.
 15738  		 */
 15739  		setFocalLength: function ( focalLength ) {
 15740  
 15741  			// see http://www.bobatkins.com/photography/technical/field_of_view.html
 15742  			var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
 15743  
 15744  			this.fov = _Math.RAD2DEG * 2 * Math.atan( vExtentSlope );
 15745  			this.updateProjectionMatrix();
 15746  
 15747  		},
 15748  
 15749  		/**
 15750  		 * Calculates the focal length from the current .fov and .filmGauge.
 15751  		 */
 15752  		getFocalLength: function () {
 15753  
 15754  			var vExtentSlope = Math.tan( _Math.DEG2RAD * 0.5 * this.fov );
 15755  
 15756  			return 0.5 * this.getFilmHeight() / vExtentSlope;
 15757  
 15758  		},
 15759  
 15760  		getEffectiveFOV: function () {
 15761  
 15762  			return _Math.RAD2DEG * 2 * Math.atan(
 15763  					Math.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom );
 15764  
 15765  		},
 15766  
 15767  		getFilmWidth: function () {
 15768  
 15769  			// film not completely covered in portrait format (aspect < 1)
 15770  			return this.filmGauge * Math.min( this.aspect, 1 );
 15771  
 15772  		},
 15773  
 15774  		getFilmHeight: function () {
 15775  
 15776  			// film not completely covered in landscape format (aspect > 1)
 15777  			return this.filmGauge / Math.max( this.aspect, 1 );
 15778  
 15779  		},
 15780  
 15781  		/**
 15782  		 * Sets an offset in a larger frustum. This is useful for multi-window or
 15783  		 * multi-monitor/multi-machine setups.
 15784  		 *
 15785  		 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
 15786  		 * the monitors are in grid like this
 15787  		 *
 15788  		 *   +---+---+---+
 15789  		 *   | A | B | C |
 15790  		 *   +---+---+---+
 15791  		 *   | D | E | F |
 15792  		 *   +---+---+---+
 15793  		 *
 15794  		 * then for each monitor you would call it like this
 15795  		 *
 15796  		 *   var w = 1920;
 15797  		 *   var h = 1080;
 15798  		 *   var fullWidth = w * 3;
 15799  		 *   var fullHeight = h * 2;
 15800  		 *
 15801  		 *   --A--
 15802  		 *   camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
 15803  		 *   --B--
 15804  		 *   camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
 15805  		 *   --C--
 15806  		 *   camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
 15807  		 *   --D--
 15808  		 *   camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
 15809  		 *   --E--
 15810  		 *   camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
 15811  		 *   --F--
 15812  		 *   camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
 15813  		 *
 15814  		 *   Note there is no reason monitors have to be the same size or in a grid.
 15815  		 */
 15816  		setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
 15817  
 15818  			this.aspect = fullWidth / fullHeight;
 15819  
 15820  			this.view = {
 15821  				fullWidth: fullWidth,
 15822  				fullHeight: fullHeight,
 15823  				offsetX: x,
 15824  				offsetY: y,
 15825  				width: width,
 15826  				height: height
 15827  			};
 15828  
 15829  			this.updateProjectionMatrix();
 15830  
 15831  		},
 15832  
 15833  		clearViewOffset: function() {
 15834  
 15835  			this.view = null;
 15836  			this.updateProjectionMatrix();
 15837  
 15838  		},
 15839  
 15840  		updateProjectionMatrix: function () {
 15841  
 15842  			var near = this.near,
 15843  				top = near * Math.tan(
 15844  						_Math.DEG2RAD * 0.5 * this.fov ) / this.zoom,
 15845  				height = 2 * top,
 15846  				width = this.aspect * height,
 15847  				left = - 0.5 * width,
 15848  				view = this.view;
 15849  
 15850  			if ( view !== null ) {
 15851  
 15852  				var fullWidth = view.fullWidth,
 15853  					fullHeight = view.fullHeight;
 15854  
 15855  				left += view.offsetX * width / fullWidth;
 15856  				top -= view.offsetY * height / fullHeight;
 15857  				width *= view.width / fullWidth;
 15858  				height *= view.height / fullHeight;
 15859  
 15860  			}
 15861  
 15862  			var skew = this.filmOffset;
 15863  			if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
 15864  
 15865  			this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );
 15866  
 15867  		},
 15868  
 15869  		toJSON: function ( meta ) {
 15870  
 15871  			var data = Object3D.prototype.toJSON.call( this, meta );
 15872  
 15873  			data.object.fov = this.fov;
 15874  			data.object.zoom = this.zoom;
 15875  
 15876  			data.object.near = this.near;
 15877  			data.object.far = this.far;
 15878  			data.object.focus = this.focus;
 15879  
 15880  			data.object.aspect = this.aspect;
 15881  
 15882  			if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
 15883  
 15884  			data.object.filmGauge = this.filmGauge;
 15885  			data.object.filmOffset = this.filmOffset;
 15886  
 15887  			return data;
 15888  
 15889  		}
 15890  
 15891  	} );
 15892  
 15893  	/**
 15894  	 * @author alteredq / http://alteredqualia.com/
 15895  	 * @author arose / http://github.com/arose
 15896  	 */
 15897  
 15898  	function OrthographicCamera( left, right, top, bottom, near, far ) {
 15899  
 15900  		Camera.call( this );
 15901  
 15902  		this.type = 'OrthographicCamera';
 15903  
 15904  		this.zoom = 1;
 15905  		this.view = null;
 15906  
 15907  		this.left = left;
 15908  		this.right = right;
 15909  		this.top = top;
 15910  		this.bottom = bottom;
 15911  
 15912  		this.near = ( near !== undefined ) ? near : 0.1;
 15913  		this.far = ( far !== undefined ) ? far : 2000;
 15914  
 15915  		this.updateProjectionMatrix();
 15916  
 15917  	}
 15918  
 15919  	OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
 15920  
 15921  		constructor: OrthographicCamera,
 15922  
 15923  		isOrthographicCamera: true,
 15924  
 15925  		copy: function ( source ) {
 15926  
 15927  			Camera.prototype.copy.call( this, source );
 15928  
 15929  			this.left = source.left;
 15930  			this.right = source.right;
 15931  			this.top = source.top;
 15932  			this.bottom = source.bottom;
 15933  			this.near = source.near;
 15934  			this.far = source.far;
 15935  
 15936  			this.zoom = source.zoom;
 15937  			this.view = source.view === null ? null : Object.assign( {}, source.view );
 15938  
 15939  			return this;
 15940  
 15941  		},
 15942  
 15943  		setViewOffset: function( fullWidth, fullHeight, x, y, width, height ) {
 15944  
 15945  			this.view = {
 15946  				fullWidth: fullWidth,
 15947  				fullHeight: fullHeight,
 15948  				offsetX: x,
 15949  				offsetY: y,
 15950  				width: width,
 15951  				height: height
 15952  			};
 15953  
 15954  			this.updateProjectionMatrix();
 15955  
 15956  		},
 15957  
 15958  		clearViewOffset: function() {
 15959  
 15960  			this.view = null;
 15961  			this.updateProjectionMatrix();
 15962  
 15963  		},
 15964  
 15965  		updateProjectionMatrix: function () {
 15966  
 15967  			var dx = ( this.right - this.left ) / ( 2 * this.zoom );
 15968  			var dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
 15969  			var cx = ( this.right + this.left ) / 2;
 15970  			var cy = ( this.top + this.bottom ) / 2;
 15971  
 15972  			var left = cx - dx;
 15973  			var right = cx + dx;
 15974  			var top = cy + dy;
 15975  			var bottom = cy - dy;
 15976  
 15977  			if ( this.view !== null ) {
 15978  
 15979  				var zoomW = this.zoom / ( this.view.width / this.view.fullWidth );
 15980  				var zoomH = this.zoom / ( this.view.height / this.view.fullHeight );
 15981  				var scaleW = ( this.right - this.left ) / this.view.width;
 15982  				var scaleH = ( this.top - this.bottom ) / this.view.height;
 15983  
 15984  				left += scaleW * ( this.view.offsetX / zoomW );
 15985  				right = left + scaleW * ( this.view.width / zoomW );
 15986  				top -= scaleH * ( this.view.offsetY / zoomH );
 15987  				bottom = top - scaleH * ( this.view.height / zoomH );
 15988  
 15989  			}
 15990  
 15991  			this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far );
 15992  
 15993  		},
 15994  
 15995  		toJSON: function ( meta ) {
 15996  
 15997  			var data = Object3D.prototype.toJSON.call( this, meta );
 15998  
 15999  			data.object.zoom = this.zoom;
 16000  			data.object.left = this.left;
 16001  			data.object.right = this.right;
 16002  			data.object.top = this.top;
 16003  			data.object.bottom = this.bottom;
 16004  			data.object.near = this.near;
 16005  			data.object.far = this.far;
 16006  
 16007  			if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
 16008  
 16009  			return data;
 16010  
 16011  		}
 16012  
 16013  	} );
 16014  
 16015  	/**
 16016  	 * @author mrdoob / http://mrdoob.com/
 16017  	 */
 16018  
 16019  	function WebGLIndexedBufferRenderer( gl, extensions, infoRender ) {
 16020  
 16021  		var mode;
 16022  
 16023  		function setMode( value ) {
 16024  
 16025  			mode = value;
 16026  
 16027  		}
 16028  
 16029  		var type, size;
 16030  
 16031  		function setIndex( index ) {
 16032  
 16033  			if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {
 16034  
 16035  				type = gl.UNSIGNED_INT;
 16036  				size = 4;
 16037  
 16038  			} else if ( index.array instanceof Uint16Array ) {
 16039  
 16040  				type = gl.UNSIGNED_SHORT;
 16041  				size = 2;
 16042  
 16043  			} else {
 16044  
 16045  				type = gl.UNSIGNED_BYTE;
 16046  				size = 1;
 16047  
 16048  			}
 16049  
 16050  		}
 16051  
 16052  		function render( start, count ) {
 16053  
 16054  			gl.drawElements( mode, count, type, start * size );
 16055  
 16056  			infoRender.calls ++;
 16057  			infoRender.vertices += count;
 16058  
 16059  			if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3;
 16060  
 16061  		}
 16062  
 16063  		function renderInstances( geometry, start, count ) {
 16064  
 16065  			var extension = extensions.get( 'ANGLE_instanced_arrays' );
 16066  
 16067  			if ( extension === null ) {
 16068  
 16069  				console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
 16070  				return;
 16071  
 16072  			}
 16073  
 16074  			extension.drawElementsInstancedANGLE( mode, count, type, start * size, geometry.maxInstancedCount );
 16075  
 16076  			infoRender.calls ++;
 16077  			infoRender.vertices += count * geometry.maxInstancedCount;
 16078  
 16079  			if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3;
 16080  
 16081  		}
 16082  
 16083  		return {
 16084  
 16085  			setMode: setMode,
 16086  			setIndex: setIndex,
 16087  			render: render,
 16088  			renderInstances: renderInstances
 16089  
 16090  		};
 16091  
 16092  	}
 16093  
 16094  	/**
 16095  	 * @author mrdoob / http://mrdoob.com/
 16096  	 */
 16097  
 16098  	function WebGLBufferRenderer( gl, extensions, infoRender ) {
 16099  
 16100  		var mode;
 16101  
 16102  		function setMode( value ) {
 16103  
 16104  			mode = value;
 16105  
 16106  		}
 16107  
 16108  		function render( start, count ) {
 16109  
 16110  			gl.drawArrays( mode, start, count );
 16111  
 16112  			infoRender.calls ++;
 16113  			infoRender.vertices += count;
 16114  
 16115  			if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3;
 16116  
 16117  		}
 16118  
 16119  		function renderInstances( geometry ) {
 16120  
 16121  			var extension = extensions.get( 'ANGLE_instanced_arrays' );
 16122  
 16123  			if ( extension === null ) {
 16124  
 16125  				console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
 16126  				return;
 16127  
 16128  			}
 16129  
 16130  			var position = geometry.attributes.position;
 16131  
 16132  			var count = 0;
 16133  
 16134  			if ( position.isInterleavedBufferAttribute ) {
 16135  
 16136  				count = position.data.count;
 16137  
 16138  				extension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount );
 16139  
 16140  			} else {
 16141  
 16142  				count = position.count;
 16143  
 16144  				extension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount );
 16145  
 16146  			}
 16147  
 16148  			infoRender.calls ++;
 16149  			infoRender.vertices += count * geometry.maxInstancedCount;
 16150  
 16151  			if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3;
 16152  
 16153  		}
 16154  
 16155  		return {
 16156  			setMode: setMode,
 16157  			render: render,
 16158  			renderInstances: renderInstances
 16159  		};
 16160  
 16161  	}
 16162  
 16163  	/**
 16164  	 * @author mrdoob / http://mrdoob.com/
 16165  	 */
 16166  
 16167  	function WebGLLights() {
 16168  
 16169  		var lights = {};
 16170  
 16171  		return {
 16172  
 16173  			get: function ( light ) {
 16174  
 16175  				if ( lights[ light.id ] !== undefined ) {
 16176  
 16177  					return lights[ light.id ];
 16178  
 16179  				}
 16180  
 16181  				var uniforms;
 16182  
 16183  				switch ( light.type ) {
 16184  
 16185  					case 'DirectionalLight':
 16186  						uniforms = {
 16187  							direction: new Vector3(),
 16188  							color: new Color(),
 16189  
 16190  							shadow: false,
 16191  							shadowBias: 0,
 16192  							shadowRadius: 1,
 16193  							shadowMapSize: new Vector2()
 16194  						};
 16195  						break;
 16196  
 16197  					case 'SpotLight':
 16198  						uniforms = {
 16199  							position: new Vector3(),
 16200  							direction: new Vector3(),
 16201  							color: new Color(),
 16202  							distance: 0,
 16203  							coneCos: 0,
 16204  							penumbraCos: 0,
 16205  							decay: 0,
 16206  
 16207  							shadow: false,
 16208  							shadowBias: 0,
 16209  							shadowRadius: 1,
 16210  							shadowMapSize: new Vector2()
 16211  						};
 16212  						break;
 16213  
 16214  					case 'PointLight':
 16215  						uniforms = {
 16216  							position: new Vector3(),
 16217  							color: new Color(),
 16218  							distance: 0,
 16219  							decay: 0,
 16220  
 16221  							shadow: false,
 16222  							shadowBias: 0,
 16223  							shadowRadius: 1,
 16224  							shadowMapSize: new Vector2()
 16225  						};
 16226  						break;
 16227  
 16228  					case 'HemisphereLight':
 16229  						uniforms = {
 16230  							direction: new Vector3(),
 16231  							skyColor: new Color(),
 16232  							groundColor: new Color()
 16233  						};
 16234  						break;
 16235  
 16236  					case 'RectAreaLight':
 16237  						uniforms = {
 16238  							color: new Color(),
 16239  							position: new Vector3(),
 16240  							halfWidth: new Vector3(),
 16241  							halfHeight: new Vector3()
 16242  							// TODO (abelnation): set RectAreaLight shadow uniforms
 16243  						};
 16244  						break;
 16245  
 16246  				}
 16247  
 16248  				lights[ light.id ] = uniforms;
 16249  
 16250  				return uniforms;
 16251  
 16252  			}
 16253  
 16254  		};
 16255  
 16256  	}
 16257  
 16258  	/**
 16259  	 * @author mrdoob / http://mrdoob.com/
 16260  	 */
 16261  
 16262  	function addLineNumbers( string ) {
 16263  
 16264  		var lines = string.split( '\n' );
 16265  
 16266  		for ( var i = 0; i < lines.length; i ++ ) {
 16267  
 16268  			lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
 16269  
 16270  		}
 16271  
 16272  		return lines.join( '\n' );
 16273  
 16274  	}
 16275  
 16276  	function WebGLShader( gl, type, string ) {
 16277  
 16278  		var shader = gl.createShader( type );
 16279  
 16280  		gl.shaderSource( shader, string );
 16281  		gl.compileShader( shader );
 16282  
 16283  		if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {
 16284  
 16285  			console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' );
 16286  
 16287  		}
 16288  
 16289  		if ( gl.getShaderInfoLog( shader ) !== '' ) {
 16290  
 16291  			console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) );
 16292  
 16293  		}
 16294  
 16295  		// --enable-privileged-webgl-extension
 16296  		// console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
 16297  
 16298  		return shader;
 16299  
 16300  	}
 16301  
 16302  	/**
 16303  	 * @author mrdoob / http://mrdoob.com/
 16304  	 */
 16305  
 16306  	var programIdCount = 0;
 16307  
 16308  	function getEncodingComponents( encoding ) {
 16309  
 16310  		switch ( encoding ) {
 16311  
 16312  			case LinearEncoding:
 16313  				return [ 'Linear','( value )' ];
 16314  			case sRGBEncoding:
 16315  				return [ 'sRGB','( value )' ];
 16316  			case RGBEEncoding:
 16317  				return [ 'RGBE','( value )' ];
 16318  			case RGBM7Encoding:
 16319  				return [ 'RGBM','( value, 7.0 )' ];
 16320  			case RGBM16Encoding:
 16321  				return [ 'RGBM','( value, 16.0 )' ];
 16322  			case RGBDEncoding:
 16323  				return [ 'RGBD','( value, 256.0 )' ];
 16324  			case GammaEncoding:
 16325  				return [ 'Gamma','( value, float( GAMMA_FACTOR ) )' ];
 16326  			default:
 16327  				throw new Error( 'unsupported encoding: ' + encoding );
 16328  
 16329  		}
 16330  
 16331  	}
 16332  
 16333  	function getTexelDecodingFunction( functionName, encoding ) {
 16334  
 16335  		var components = getEncodingComponents( encoding );
 16336  		return "vec4 " + functionName + "( vec4 value ) { return " + components[ 0 ] + "ToLinear" + components[ 1 ] + "; }";
 16337  
 16338  	}
 16339  
 16340  	function getTexelEncodingFunction( functionName, encoding ) {
 16341  
 16342  		var components = getEncodingComponents( encoding );
 16343  		return "vec4 " + functionName + "( vec4 value ) { return LinearTo" + components[ 0 ] + components[ 1 ] + "; }";
 16344  
 16345  	}
 16346  
 16347  	function getToneMappingFunction( functionName, toneMapping ) {
 16348  
 16349  		var toneMappingName;
 16350  
 16351  		switch ( toneMapping ) {
 16352  
 16353  			case LinearToneMapping:
 16354  				toneMappingName = "Linear";
 16355  				break;
 16356  
 16357  			case ReinhardToneMapping:
 16358  				toneMappingName = "Reinhard";
 16359  				break;
 16360  
 16361  			case Uncharted2ToneMapping:
 16362  				toneMappingName = "Uncharted2";
 16363  				break;
 16364  
 16365  			case CineonToneMapping:
 16366  				toneMappingName = "OptimizedCineon";
 16367  				break;
 16368  
 16369  			default:
 16370  				throw new Error( 'unsupported toneMapping: ' + toneMapping );
 16371  
 16372  		}
 16373  
 16374  		return "vec3 " + functionName + "( vec3 color ) { return " + toneMappingName + "ToneMapping( color ); }";
 16375  
 16376  	}
 16377  
 16378  	function generateExtensions( extensions, parameters, rendererExtensions ) {
 16379  
 16380  		extensions = extensions || {};
 16381  
 16382  		var chunks = [
 16383  			( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',
 16384  			( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '',
 16385  			( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '',
 16386  			( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : ''
 16387  		];
 16388  
 16389  		return chunks.filter( filterEmptyLine ).join( '\n' );
 16390  
 16391  	}
 16392  
 16393  	function generateDefines( defines ) {
 16394  
 16395  		var chunks = [];
 16396  
 16397  		for ( var name in defines ) {
 16398  
 16399  			var value = defines[ name ];
 16400  
 16401  			if ( value === false ) continue;
 16402  
 16403  			chunks.push( '#define ' + name + ' ' + value );
 16404  
 16405  		}
 16406  
 16407  		return chunks.join( '\n' );
 16408  
 16409  	}
 16410  
 16411  	function fetchAttributeLocations( gl, program, identifiers ) {
 16412  
 16413  		var attributes = {};
 16414  
 16415  		var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );
 16416  
 16417  		for ( var i = 0; i < n; i ++ ) {
 16418  
 16419  			var info = gl.getActiveAttrib( program, i );
 16420  			var name = info.name;
 16421  
 16422  			// console.log("THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:", name, i );
 16423  
 16424  			attributes[ name ] = gl.getAttribLocation( program, name );
 16425  
 16426  		}
 16427  
 16428  		return attributes;
 16429  
 16430  	}
 16431  
 16432  	function filterEmptyLine( string ) {
 16433  
 16434  		return string !== '';
 16435  
 16436  	}
 16437  
 16438  	function replaceLightNums( string, parameters ) {
 16439  
 16440  		return string
 16441  			.replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
 16442  			.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
 16443  			.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
 16444  			.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
 16445  			.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights );
 16446  
 16447  	}
 16448  
 16449  	function parseIncludes( string ) {
 16450  
 16451  		var pattern = /#include +<([\w\d.]+)>/g;
 16452  
 16453  		function replace( match, include ) {
 16454  
 16455  			var replace = ShaderChunk[ include ];
 16456  
 16457  			if ( replace === undefined ) {
 16458  
 16459  				throw new Error( 'Can not resolve #include <' + include + '>' );
 16460  
 16461  			}
 16462  
 16463  			return parseIncludes( replace );
 16464  
 16465  		}
 16466  
 16467  		return string.replace( pattern, replace );
 16468  
 16469  	}
 16470  
 16471  	function unrollLoops( string ) {
 16472  
 16473  		var pattern = /for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
 16474  
 16475  		function replace( match, start, end, snippet ) {
 16476  
 16477  			var unroll = '';
 16478  
 16479  			for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) {
 16480  
 16481  				unroll += snippet.replace( /\[ i \]/g, '[ ' + i + ' ]' );
 16482  
 16483  			}
 16484  
 16485  			return unroll;
 16486  
 16487  		}
 16488  
 16489  		return string.replace( pattern, replace );
 16490  
 16491  	}
 16492  
 16493  	function WebGLProgram( renderer, code, material, parameters ) {
 16494  
 16495  		var gl = renderer.context;
 16496  
 16497  		var extensions = material.extensions;
 16498  		var defines = material.defines;
 16499  
 16500  		var vertexShader = material.__webglShader.vertexShader;
 16501  		var fragmentShader = material.__webglShader.fragmentShader;
 16502  
 16503  		var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
 16504  
 16505  		if ( parameters.shadowMapType === PCFShadowMap ) {
 16506  
 16507  			shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
 16508  
 16509  		} else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
 16510  
 16511  			shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
 16512  
 16513  		}
 16514  
 16515  		var envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
 16516  		var envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
 16517  		var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
 16518  
 16519  		if ( parameters.envMap ) {
 16520  
 16521  			switch ( material.envMap.mapping ) {
 16522  
 16523  				case CubeReflectionMapping:
 16524  				case CubeRefractionMapping:
 16525  					envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
 16526  					break;
 16527  
 16528  				case CubeUVReflectionMapping:
 16529  				case CubeUVRefractionMapping:
 16530  					envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
 16531  					break;
 16532  
 16533  				case EquirectangularReflectionMapping:
 16534  				case EquirectangularRefractionMapping:
 16535  					envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC';
 16536  					break;
 16537  
 16538  				case SphericalReflectionMapping:
 16539  					envMapTypeDefine = 'ENVMAP_TYPE_SPHERE';
 16540  					break;
 16541  
 16542  			}
 16543  
 16544  			switch ( material.envMap.mapping ) {
 16545  
 16546  				case CubeRefractionMapping:
 16547  				case EquirectangularRefractionMapping:
 16548  					envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
 16549  					break;
 16550  
 16551  			}
 16552  
 16553  			switch ( material.combine ) {
 16554  
 16555  				case MultiplyOperation:
 16556  					envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
 16557  					break;
 16558  
 16559  				case MixOperation:
 16560  					envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
 16561  					break;
 16562  
 16563  				case AddOperation:
 16564  					envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
 16565  					break;
 16566  
 16567  			}
 16568  
 16569  		}
 16570  
 16571  		var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;
 16572  
 16573  		// console.log( 'building new program ' );
 16574  
 16575  		//
 16576  
 16577  		var customExtensions = generateExtensions( extensions, parameters, renderer.extensions );
 16578  
 16579  		var customDefines = generateDefines( defines );
 16580  
 16581  		//
 16582  
 16583  		var program = gl.createProgram();
 16584  
 16585  		var prefixVertex, prefixFragment;
 16586  
 16587  		if ( material.isRawShaderMaterial ) {
 16588  
 16589  			prefixVertex = [
 16590  
 16591  				customDefines,
 16592  
 16593  				'\n'
 16594  
 16595  			].filter( filterEmptyLine ).join( '\n' );
 16596  
 16597  			prefixFragment = [
 16598  
 16599  				customExtensions,
 16600  				customDefines,
 16601  
 16602  				'\n'
 16603  
 16604  			].filter( filterEmptyLine ).join( '\n' );
 16605  
 16606  		} else {
 16607  
 16608  			prefixVertex = [
 16609  
 16610  	        
 16611  				'precision ' + parameters.precision + ' float;',
 16612  				'precision ' + parameters.precision + ' int;',
 16613  
 16614  				'#define SHADER_NAME ' + material.__webglShader.name,
 16615  
 16616  				customDefines,
 16617  
 16618  				parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',
 16619  
 16620  				'#define GAMMA_FACTOR ' + gammaFactorDefine,
 16621  
 16622  				'#define MAX_BONES ' + parameters.maxBones,
 16623  				( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
 16624  				( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',
 16625  
 16626  
 16627  				parameters.map ? '#define USE_MAP' : '',
 16628  				parameters.envMap ? '#define USE_ENVMAP' : '',
 16629  				parameters.envMap ? '#define ' + envMapModeDefine : '',
 16630  				parameters.lightMap ? '#define USE_LIGHTMAP' : '',
 16631  				parameters.aoMap ? '#define USE_AOMAP' : '',
 16632  				parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
 16633  				parameters.bumpMap ? '#define USE_BUMPMAP' : '',
 16634  				parameters.normalMap ? '#define USE_NORMALMAP' : '',
 16635  				parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
 16636  				parameters.specularMap ? '#define USE_SPECULARMAP' : '',
 16637  				parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
 16638  				parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
 16639  				parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
 16640  				parameters.vertexColors ? '#define USE_COLOR' : '',
 16641  
 16642  				parameters.flatShading ? '#define FLAT_SHADED' : '',
 16643  
 16644  				parameters.skinning ? '#define USE_SKINNING' : '',
 16645  				parameters.useVertexTexture ? '#define BONE_TEXTURE' : '',
 16646  
 16647  				parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
 16648  				parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
 16649  				parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
 16650  				parameters.flipSided ? '#define FLIP_SIDED' : '',
 16651  
 16652  				'#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,
 16653  
 16654  				parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
 16655  				parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
 16656  
 16657  				parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
 16658  
 16659  				parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
 16660  				parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
 16661  
 16662  				'uniform mat4 modelMatrix;',
 16663  				'uniform mat4 modelViewMatrix;',
 16664  				'uniform mat4 projectionMatrix;',
 16665  				'uniform mat4 viewMatrix;',
 16666  				'uniform mat3 normalMatrix;',
 16667  				'uniform vec3 cameraPosition;',
 16668  
 16669  				'attribute vec3 position;',
 16670  				'attribute vec3 normal;',
 16671  				'attribute vec2 uv;',
 16672  
 16673  				'#ifdef USE_COLOR',
 16674  
 16675  				'	attribute vec3 color;',
 16676  
 16677  				'#endif',
 16678  
 16679  				'#ifdef USE_MORPHTARGETS',
 16680  
 16681  				'	attribute vec3 morphTarget0;',
 16682  				'	attribute vec3 morphTarget1;',
 16683  				'	attribute vec3 morphTarget2;',
 16684  				'	attribute vec3 morphTarget3;',
 16685  
 16686  				'	#ifdef USE_MORPHNORMALS',
 16687  
 16688  				'		attribute vec3 morphNormal0;',
 16689  				'		attribute vec3 morphNormal1;',
 16690  				'		attribute vec3 morphNormal2;',
 16691  				'		attribute vec3 morphNormal3;',
 16692  
 16693  				'	#else',
 16694  
 16695  				'		attribute vec3 morphTarget4;',
 16696  				'		attribute vec3 morphTarget5;',
 16697  				'		attribute vec3 morphTarget6;',
 16698  				'		attribute vec3 morphTarget7;',
 16699  
 16700  				'	#endif',
 16701  
 16702  				'#endif',
 16703  
 16704  				'#ifdef USE_SKINNING',
 16705  
 16706  				'	attribute vec4 skinIndex;',
 16707  				'	attribute vec4 skinWeight;',
 16708  
 16709  				'#endif',
 16710  
 16711  				'\n'
 16712  
 16713  			].filter( filterEmptyLine ).join( '\n' );
 16714  
 16715  			prefixFragment = [
 16716  
 16717  				customExtensions,
 16718  
 16719  				'precision ' + parameters.precision + ' float;',
 16720  				'precision ' + parameters.precision + ' int;',
 16721  
 16722  				'#define SHADER_NAME ' + material.__webglShader.name,
 16723  
 16724  				customDefines,
 16725  
 16726  				parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '',
 16727  
 16728  				'#define GAMMA_FACTOR ' + gammaFactorDefine,
 16729  
 16730  				( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
 16731  				( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',
 16732  
 16733  				parameters.map ? '#define USE_MAP' : '',
 16734  				parameters.envMap ? '#define USE_ENVMAP' : '',
 16735  				parameters.envMap ? '#define ' + envMapTypeDefine : '',
 16736  				parameters.envMap ? '#define ' + envMapModeDefine : '',
 16737  				parameters.envMap ? '#define ' + envMapBlendingDefine : '',
 16738  				parameters.lightMap ? '#define USE_LIGHTMAP' : '',
 16739  				parameters.aoMap ? '#define USE_AOMAP' : '',
 16740  				parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
 16741  				parameters.bumpMap ? '#define USE_BUMPMAP' : '',
 16742  				parameters.normalMap ? '#define USE_NORMALMAP' : '',
 16743  				parameters.specularMap ? '#define USE_SPECULARMAP' : '',
 16744  				parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
 16745  				parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
 16746  				parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
 16747  				parameters.vertexColors ? '#define USE_COLOR' : '',
 16748  
 16749  				parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
 16750  
 16751  				parameters.flatShading ? '#define FLAT_SHADED' : '',
 16752  
 16753  				parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
 16754  				parameters.flipSided ? '#define FLIP_SIDED' : '',
 16755  
 16756  				'#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,
 16757  				'#define UNION_CLIPPING_PLANES ' + (parameters.numClippingPlanes - parameters.numClipIntersection),
 16758  
 16759  				parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
 16760  				parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
 16761  
 16762  				parameters.premultipliedAlpha ? "#define PREMULTIPLIED_ALPHA" : '',
 16763  
 16764  				parameters.physicallyCorrectLights ? "#define PHYSICALLY_CORRECT_LIGHTS" : '',
 16765  
 16766  				parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
 16767  				parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
 16768  
 16769  				parameters.envMap && renderer.extensions.get( 'EXT_shader_texture_lod' ) ? '#define TEXTURE_LOD_EXT' : '',
 16770  
 16771  				'uniform mat4 viewMatrix;',
 16772  				'uniform vec3 cameraPosition;',
 16773  
 16774  				( parameters.toneMapping !== NoToneMapping ) ? "#define TONE_MAPPING" : '',
 16775  				( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '',  // this code is required here because it is used by the toneMapping() function defined below
 16776  				( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( "toneMapping", parameters.toneMapping ) : '',
 16777  
 16778  				( parameters.outputEncoding || parameters.mapEncoding || parameters.envMapEncoding || parameters.emissiveMapEncoding ) ? ShaderChunk[ 'encodings_pars_fragment' ] : '', // this code is required here because it is used by the various encoding/decoding function defined below
 16779  				parameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
 16780  				parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',
 16781  				parameters.emissiveMapEncoding ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',
 16782  				parameters.outputEncoding ? getTexelEncodingFunction( "linearToOutputTexel", parameters.outputEncoding ) : '',
 16783  
 16784  				parameters.depthPacking ? "#define DEPTH_PACKING " + material.depthPacking : '',
 16785  
 16786  				'\n'
 16787  
 16788  			].filter( filterEmptyLine ).join( '\n' );
 16789  
 16790  		}
 16791  
 16792  		vertexShader = parseIncludes( vertexShader, parameters );
 16793  		vertexShader = replaceLightNums( vertexShader, parameters );
 16794  
 16795  		fragmentShader = parseIncludes( fragmentShader, parameters );
 16796  		fragmentShader = replaceLightNums( fragmentShader, parameters );
 16797  
 16798  		if ( ! material.isShaderMaterial ) {
 16799  
 16800  			vertexShader = unrollLoops( vertexShader );
 16801  			fragmentShader = unrollLoops( fragmentShader );
 16802  
 16803  		}
 16804  
 16805  		var vertexGlsl = prefixVertex + vertexShader;
 16806  		var fragmentGlsl = prefixFragment + fragmentShader;
 16807  
 16808  		// console.log( '*VERTEX*', vertexGlsl );
 16809  		// console.log( '*FRAGMENT*', fragmentGlsl );
 16810  
 16811  		var glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
 16812  		var glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );
 16813  
 16814  		gl.attachShader( program, glVertexShader );
 16815  		gl.attachShader( program, glFragmentShader );
 16816  
 16817  		// Force a particular attribute to index 0.
 16818  
 16819  		if ( material.index0AttributeName !== undefined ) {
 16820  
 16821  			gl.bindAttribLocation( program, 0, material.index0AttributeName );
 16822  
 16823  		} else if ( parameters.morphTargets === true ) {
 16824  
 16825  			// programs with morphTargets displace position out of attribute 0
 16826  			gl.bindAttribLocation( program, 0, 'position' );
 16827  
 16828  		}
 16829  
 16830  		gl.linkProgram( program );
 16831  
 16832  		var programLog = gl.getProgramInfoLog( program );
 16833  		var vertexLog = gl.getShaderInfoLog( glVertexShader );
 16834  		var fragmentLog = gl.getShaderInfoLog( glFragmentShader );
 16835  
 16836  		var runnable = true;
 16837  		var haveDiagnostics = true;
 16838  
 16839  		// console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) );
 16840  		// console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) );
 16841  
 16842  		if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {
 16843  
 16844  			runnable = false;
 16845  
 16846  			console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog );
 16847  
 16848  		} else if ( programLog !== '' ) {
 16849  
 16850  			console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog );
 16851  
 16852  		} else if ( vertexLog === '' || fragmentLog === '' ) {
 16853  
 16854  			haveDiagnostics = false;
 16855  
 16856  		}
 16857  
 16858  		if ( haveDiagnostics ) {
 16859  
 16860  			this.diagnostics = {
 16861  
 16862  				runnable: runnable,
 16863  				material: material,
 16864  
 16865  				programLog: programLog,
 16866  
 16867  				vertexShader: {
 16868  
 16869  					log: vertexLog,
 16870  					prefix: prefixVertex
 16871  
 16872  				},
 16873  
 16874  				fragmentShader: {
 16875  
 16876  					log: fragmentLog,
 16877  					prefix: prefixFragment
 16878  
 16879  				}
 16880  
 16881  			};
 16882  
 16883  		}
 16884  
 16885  		// clean up
 16886  
 16887  		gl.deleteShader( glVertexShader );
 16888  		gl.deleteShader( glFragmentShader );
 16889  
 16890  		// set up caching for uniform locations
 16891  
 16892  		var cachedUniforms;
 16893  
 16894  		this.getUniforms = function() {
 16895  
 16896  			if ( cachedUniforms === undefined ) {
 16897  
 16898  				cachedUniforms =
 16899  					new WebGLUniforms( gl, program, renderer );
 16900  
 16901  			}
 16902  
 16903  			return cachedUniforms;
 16904  
 16905  		};
 16906  
 16907  		// set up caching for attribute locations
 16908  
 16909  		var cachedAttributes;
 16910  
 16911  		this.getAttributes = function() {
 16912  
 16913  			if ( cachedAttributes === undefined ) {
 16914  
 16915  				cachedAttributes = fetchAttributeLocations( gl, program );
 16916  
 16917  			}
 16918  
 16919  			return cachedAttributes;
 16920  
 16921  		};
 16922  
 16923  		// free resource
 16924  
 16925  		this.destroy = function() {
 16926  
 16927  			gl.deleteProgram( program );
 16928  			this.program = undefined;
 16929  
 16930  		};
 16931  
 16932  		// DEPRECATED
 16933  
 16934  		Object.defineProperties( this, {
 16935  
 16936  			uniforms: {
 16937  				get: function() {
 16938  
 16939  					console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' );
 16940  					return this.getUniforms();
 16941  
 16942  				}
 16943  			},
 16944  
 16945  			attributes: {
 16946  				get: function() {
 16947  
 16948  					console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' );
 16949  					return this.getAttributes();
 16950  
 16951  				}
 16952  			}
 16953  
 16954  		} );
 16955  
 16956  
 16957  		//
 16958  
 16959  		this.id = programIdCount ++;
 16960  		this.code = code;
 16961  		this.usedTimes = 1;
 16962  		this.program = program;
 16963  		this.vertexShader = glVertexShader;
 16964  		this.fragmentShader = glFragmentShader;
 16965  
 16966  		return this;
 16967  
 16968  	}
 16969  
 16970  	/**
 16971  	 * @author mrdoob / http://mrdoob.com/
 16972  	 */
 16973  
 16974  	function WebGLPrograms( renderer, capabilities ) {
 16975  
 16976  		var programs = [];
 16977  
 16978  		var shaderIDs = {
 16979  			MeshDepthMaterial: 'depth',
 16980  			MeshNormalMaterial: 'normal',
 16981  			MeshBasicMaterial: 'basic',
 16982  			MeshLambertMaterial: 'lambert',
 16983  			MeshPhongMaterial: 'phong',
 16984  			MeshToonMaterial: 'phong',
 16985  			MeshStandardMaterial: 'physical',
 16986  			MeshPhysicalMaterial: 'physical',
 16987  			LineBasicMaterial: 'basic',
 16988  			LineDashedMaterial: 'dashed',
 16989  			PointsMaterial: 'points'
 16990  		};
 16991  
 16992  		var parameterNames = [
 16993  			"precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding",
 16994  			"lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap",
 16995  			"roughnessMap", "metalnessMap", "gradientMap",
 16996  			"alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp",
 16997  			"flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
 16998  			"maxBones", "useVertexTexture", "morphTargets", "morphNormals",
 16999  			"maxMorphTargets", "maxMorphNormals", "premultipliedAlpha",
 17000  			"numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights",
 17001  			"shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights',
 17002  			"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking"
 17003  		];
 17004  
 17005  
 17006  		function allocateBones( object ) {
 17007  
 17008  			if ( capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture ) {
 17009  
 17010  				return 1024;
 17011  
 17012  			} else {
 17013  
 17014  				// default for when object is not specified
 17015  				// ( for example when prebuilding shader to be used with multiple objects )
 17016  				//
 17017  				//  - leave some extra space for other uniforms
 17018  				//  - limit here is ANGLE's 254 max uniform vectors
 17019  				//    (up to 54 should be safe)
 17020  
 17021  				var nVertexUniforms = capabilities.maxVertexUniforms;
 17022  				var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
 17023  
 17024  				var maxBones = nVertexMatrices;
 17025  
 17026  				if ( object !== undefined && (object && object.isSkinnedMesh) ) {
 17027  
 17028  					maxBones = Math.min( object.skeleton.bones.length, maxBones );
 17029  
 17030  					if ( maxBones < object.skeleton.bones.length ) {
 17031  
 17032  						console.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' );
 17033  
 17034  					}
 17035  
 17036  				}
 17037  
 17038  				return maxBones;
 17039  
 17040  			}
 17041  
 17042  		}
 17043  
 17044  		function getTextureEncodingFromMap( map, gammaOverrideLinear ) {
 17045  
 17046  			var encoding;
 17047  
 17048  			if ( ! map ) {
 17049  
 17050  				encoding = LinearEncoding;
 17051  
 17052  			} else if ( map.isTexture ) {
 17053  
 17054  				encoding = map.encoding;
 17055  
 17056  			} else if ( map.isWebGLRenderTarget ) {
 17057  
 17058  				console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." );
 17059  				encoding = map.texture.encoding;
 17060  
 17061  			}
 17062  
 17063  			// add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.
 17064  			if ( encoding === LinearEncoding && gammaOverrideLinear ) {
 17065  
 17066  				encoding = GammaEncoding;
 17067  
 17068  			}
 17069  
 17070  			return encoding;
 17071  
 17072  		}
 17073  
 17074  		this.getParameters = function ( material, lights, fog, nClipPlanes, nClipIntersection, object ) {
 17075  
 17076  			var shaderID = shaderIDs[ material.type ];
 17077  
 17078  			// heuristics to create shader parameters according to lights in the scene
 17079  			// (not to blow over maxLights budget)
 17080  
 17081  			var maxBones = allocateBones( object );
 17082  			var precision = renderer.getPrecision();
 17083  
 17084  			if ( material.precision !== null ) {
 17085  
 17086  				precision = capabilities.getMaxPrecision( material.precision );
 17087  
 17088  				if ( precision !== material.precision ) {
 17089  
 17090  					console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
 17091  
 17092  				}
 17093  
 17094  			}
 17095  
 17096  			var currentRenderTarget = renderer.getCurrentRenderTarget();
 17097  
 17098  			var parameters = {
 17099  
 17100  				shaderID: shaderID,
 17101  
 17102  				precision: precision,
 17103  				supportsVertexTextures: capabilities.vertexTextures,
 17104  				outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ),
 17105  				map: !! material.map,
 17106  				mapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ),
 17107  				envMap: !! material.envMap,
 17108  				envMapMode: material.envMap && material.envMap.mapping,
 17109  				envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ),
 17110  				envMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ),
 17111  				lightMap: !! material.lightMap,
 17112  				aoMap: !! material.aoMap,
 17113  				emissiveMap: !! material.emissiveMap,
 17114  				emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ),
 17115  				bumpMap: !! material.bumpMap,
 17116  				normalMap: !! material.normalMap,
 17117  				displacementMap: !! material.displacementMap,
 17118  				roughnessMap: !! material.roughnessMap,
 17119  				metalnessMap: !! material.metalnessMap,
 17120  				specularMap: !! material.specularMap,
 17121  				alphaMap: !! material.alphaMap,
 17122  
 17123  				gradientMap: !! material.gradientMap,
 17124  
 17125  				combine: material.combine,
 17126  
 17127  				vertexColors: material.vertexColors,
 17128  
 17129  				fog: !! fog,
 17130  				useFog: material.fog,
 17131  				fogExp: (fog && fog.isFogExp2),
 17132  
 17133  				flatShading: material.shading === FlatShading,
 17134  
 17135  				sizeAttenuation: material.sizeAttenuation,
 17136  				logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer,
 17137  
 17138  				skinning: material.skinning,
 17139  				maxBones: maxBones,
 17140  				useVertexTexture: capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture,
 17141  
 17142  				morphTargets: material.morphTargets,
 17143  				morphNormals: material.morphNormals,
 17144  				maxMorphTargets: renderer.maxMorphTargets,
 17145  				maxMorphNormals: renderer.maxMorphNormals,
 17146  
 17147  				numDirLights: lights.directional.length,
 17148  				numPointLights: lights.point.length,
 17149  				numSpotLights: lights.spot.length,
 17150  				numRectAreaLights: lights.rectArea.length,
 17151  				numHemiLights: lights.hemi.length,
 17152  
 17153  				numClippingPlanes: nClipPlanes,
 17154  				numClipIntersection: nClipIntersection,
 17155  
 17156  				shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && lights.shadows.length > 0,
 17157  				shadowMapType: renderer.shadowMap.type,
 17158  
 17159  				toneMapping: renderer.toneMapping,
 17160  				physicallyCorrectLights: renderer.physicallyCorrectLights,
 17161  
 17162  				premultipliedAlpha: material.premultipliedAlpha,
 17163  
 17164  				alphaTest: material.alphaTest,
 17165  				doubleSided: material.side === DoubleSide,
 17166  				flipSided: material.side === BackSide,
 17167  
 17168  				depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false
 17169  
 17170  			};
 17171  
 17172  			return parameters;
 17173  
 17174  		};
 17175  
 17176  		this.getProgramCode = function ( material, parameters ) {
 17177  
 17178  			var array = [];
 17179  
 17180  			if ( parameters.shaderID ) {
 17181  
 17182  				array.push( parameters.shaderID );
 17183  
 17184  			} else {
 17185  
 17186  				array.push( material.fragmentShader );
 17187  				array.push( material.vertexShader );
 17188  
 17189  			}
 17190  
 17191  			if ( material.defines !== undefined ) {
 17192  
 17193  				for ( var name in material.defines ) {
 17194  
 17195  					array.push( name );
 17196  					array.push( material.defines[ name ] );
 17197  
 17198  				}
 17199  
 17200  			}
 17201  
 17202  			for ( var i = 0; i < parameterNames.length; i ++ ) {
 17203  
 17204  				array.push( parameters[ parameterNames[ i ] ] );
 17205  
 17206  			}
 17207  
 17208  			return array.join();
 17209  
 17210  		};
 17211  
 17212  		this.acquireProgram = function ( material, parameters, code ) {
 17213  
 17214  			var program;
 17215  
 17216  			// Check if code has been already compiled
 17217  			for ( var p = 0, pl = programs.length; p < pl; p ++ ) {
 17218  
 17219  				var programInfo = programs[ p ];
 17220  
 17221  				if ( programInfo.code === code ) {
 17222  
 17223  					program = programInfo;
 17224  					++ program.usedTimes;
 17225  
 17226  					break;
 17227  
 17228  				}
 17229  
 17230  			}
 17231  
 17232  			if ( program === undefined ) {
 17233  
 17234  				program = new WebGLProgram( renderer, code, material, parameters );
 17235  				programs.push( program );
 17236  
 17237  			}
 17238  
 17239  			return program;
 17240  
 17241  		};
 17242  
 17243  		this.releaseProgram = function( program ) {
 17244  
 17245  			if ( -- program.usedTimes === 0 ) {
 17246  
 17247  				// Remove from unordered set
 17248  				var i = programs.indexOf( program );
 17249  				programs[ i ] = programs[ programs.length - 1 ];
 17250  				programs.pop();
 17251  
 17252  				// Free WebGL resources
 17253  				program.destroy();
 17254  
 17255  			}
 17256  
 17257  		};
 17258  
 17259  		// Exposed for resource monitoring & error feedback via renderer.info:
 17260  		this.programs = programs;
 17261  
 17262  	}
 17263  
 17264  	/**
 17265  	 * @author mrdoob / http://mrdoob.com/
 17266  	 */
 17267  
 17268  	function WebGLGeometries( gl, properties, info ) {
 17269  
 17270  		var geometries = {};
 17271  
 17272  		function onGeometryDispose( event ) {
 17273  
 17274  			var geometry = event.target;
 17275  			var buffergeometry = geometries[ geometry.id ];
 17276  
 17277  			if ( buffergeometry.index !== null ) {
 17278  
 17279  				deleteAttribute( buffergeometry.index );
 17280  
 17281  			}
 17282  
 17283  			deleteAttributes( buffergeometry.attributes );
 17284  
 17285  			geometry.removeEventListener( 'dispose', onGeometryDispose );
 17286  
 17287  			delete geometries[ geometry.id ];
 17288  
 17289  			// TODO
 17290  
 17291  			var property = properties.get( geometry );
 17292  
 17293  			if ( property.wireframe ) {
 17294  
 17295  				deleteAttribute( property.wireframe );
 17296  
 17297  			}
 17298  
 17299  			properties.delete( geometry );
 17300  
 17301  			var bufferproperty = properties.get( buffergeometry );
 17302  
 17303  			if ( bufferproperty.wireframe ) {
 17304  
 17305  				deleteAttribute( bufferproperty.wireframe );
 17306  
 17307  			}
 17308  
 17309  			properties.delete( buffergeometry );
 17310  
 17311  			//
 17312  
 17313  			info.memory.geometries --;
 17314  
 17315  		}
 17316  
 17317  		function getAttributeBuffer( attribute ) {
 17318  
 17319  			if ( attribute.isInterleavedBufferAttribute ) {
 17320  
 17321  				return properties.get( attribute.data ).__webglBuffer;
 17322  
 17323  			}
 17324  
 17325  			return properties.get( attribute ).__webglBuffer;
 17326  
 17327  		}
 17328  
 17329  		function deleteAttribute( attribute ) {
 17330  
 17331  			var buffer = getAttributeBuffer( attribute );
 17332  
 17333  			if ( buffer !== undefined ) {
 17334  
 17335  				gl.deleteBuffer( buffer );
 17336  				removeAttributeBuffer( attribute );
 17337  
 17338  			}
 17339  
 17340  		}
 17341  
 17342  		function deleteAttributes( attributes ) {
 17343  
 17344  			for ( var name in attributes ) {
 17345  
 17346  				deleteAttribute( attributes[ name ] );
 17347  
 17348  			}
 17349  
 17350  		}
 17351  
 17352  		function removeAttributeBuffer( attribute ) {
 17353  
 17354  			if ( attribute.isInterleavedBufferAttribute ) {
 17355  
 17356  				properties.delete( attribute.data );
 17357  
 17358  			} else {
 17359  
 17360  				properties.delete( attribute );
 17361  
 17362  			}
 17363  
 17364  		}
 17365  
 17366  		return {
 17367  
 17368  			get: function ( object ) {
 17369  
 17370  				var geometry = object.geometry;
 17371  
 17372  				if ( geometries[ geometry.id ] !== undefined ) {
 17373  
 17374  					return geometries[ geometry.id ];
 17375  
 17376  				}
 17377  
 17378  				geometry.addEventListener( 'dispose', onGeometryDispose );
 17379  
 17380  				var buffergeometry;
 17381  
 17382  				if ( geometry.isBufferGeometry ) {
 17383  
 17384  					buffergeometry = geometry;
 17385  
 17386  				} else if ( geometry.isGeometry ) {
 17387  
 17388  					if ( geometry._bufferGeometry === undefined ) {
 17389  
 17390  						geometry._bufferGeometry = new BufferGeometry().setFromObject( object );
 17391  
 17392  					}
 17393  
 17394  					buffergeometry = geometry._bufferGeometry;
 17395  
 17396  				}
 17397  
 17398  				geometries[ geometry.id ] = buffergeometry;
 17399  
 17400  				info.memory.geometries ++;
 17401  
 17402  				return buffergeometry;
 17403  
 17404  			}
 17405  
 17406  		};
 17407  
 17408  	}
 17409  
 17410  	/**
 17411  	 * @author mrdoob / http://mrdoob.com/
 17412  	 */
 17413  
 17414  	function WebGLObjects( gl, properties, info ) {
 17415  
 17416  		var geometries = new WebGLGeometries( gl, properties, info );
 17417  
 17418  		//
 17419  
 17420  		function update( object ) {
 17421  
 17422  			// TODO: Avoid updating twice (when using shadowMap). Maybe add frame counter.
 17423  
 17424  			var geometry = geometries.get( object );
 17425  
 17426  			if ( object.geometry.isGeometry ) {
 17427  
 17428  				geometry.updateFromObject( object );
 17429  
 17430  			}
 17431  
 17432  			var index = geometry.index;
 17433  			var attributes = geometry.attributes;
 17434  
 17435  			if ( index !== null ) {
 17436  
 17437  				updateAttribute( index, gl.ELEMENT_ARRAY_BUFFER );
 17438  
 17439  			}
 17440  
 17441  			for ( var name in attributes ) {
 17442  
 17443  				updateAttribute( attributes[ name ], gl.ARRAY_BUFFER );
 17444  
 17445  			}
 17446  
 17447  			// morph targets
 17448  
 17449  			var morphAttributes = geometry.morphAttributes;
 17450  
 17451  			for ( var name in morphAttributes ) {
 17452  
 17453  				var array = morphAttributes[ name ];
 17454  
 17455  				for ( var i = 0, l = array.length; i < l; i ++ ) {
 17456  
 17457  					updateAttribute( array[ i ], gl.ARRAY_BUFFER );
 17458  
 17459  				}
 17460  
 17461  			}
 17462  
 17463  			return geometry;
 17464  
 17465  		}
 17466  
 17467  		function updateAttribute( attribute, bufferType ) {
 17468  
 17469  			var data = ( attribute.isInterleavedBufferAttribute ) ? attribute.data : attribute;
 17470  
 17471  			var attributeProperties = properties.get( data );
 17472  
 17473  			if ( attributeProperties.__webglBuffer === undefined ) {
 17474  
 17475  				createBuffer( attributeProperties, data, bufferType );
 17476  
 17477  			} else if ( attributeProperties.version !== data.version ) {
 17478  
 17479  				updateBuffer( attributeProperties, data, bufferType );
 17480  
 17481  			}
 17482  
 17483  		}
 17484  
 17485  		function createBuffer( attributeProperties, data, bufferType ) {
 17486  
 17487  			attributeProperties.__webglBuffer = gl.createBuffer();
 17488  			gl.bindBuffer( bufferType, attributeProperties.__webglBuffer );
 17489  
 17490  			var usage = data.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;
 17491  
 17492  			gl.bufferData( bufferType, data.array, usage );
 17493  
 17494  			var type = gl.FLOAT;
 17495  			var array = data.array;
 17496  
 17497  			if ( array instanceof Float32Array ) {
 17498  
 17499  				type = gl.FLOAT;
 17500  
 17501  			} else if ( array instanceof Float64Array ) {
 17502  
 17503  				console.warn( "Unsupported data buffer format: Float64Array" );
 17504  
 17505  			} else if ( array instanceof Uint16Array ) {
 17506  
 17507  				type = gl.UNSIGNED_SHORT;
 17508  
 17509  			} else if ( array instanceof Int16Array ) {
 17510  
 17511  				type = gl.SHORT;
 17512  
 17513  			} else if ( array instanceof Uint32Array ) {
 17514  
 17515  				type = gl.UNSIGNED_INT;
 17516  
 17517  			} else if ( array instanceof Int32Array ) {
 17518  
 17519  				type = gl.INT;
 17520  
 17521  			} else if ( array instanceof Int8Array ) {
 17522  
 17523  				type = gl.BYTE;
 17524  
 17525  			} else if ( array instanceof Uint8Array ) {
 17526  
 17527  				type = gl.UNSIGNED_BYTE;
 17528  
 17529  			}
 17530  
 17531  			attributeProperties.bytesPerElement = array.BYTES_PER_ELEMENT;
 17532  			attributeProperties.type = type;
 17533  			attributeProperties.version = data.version;
 17534  
 17535  			data.onUploadCallback();
 17536  
 17537  		}
 17538  
 17539  		function updateBuffer( attributeProperties, data, bufferType ) {
 17540  
 17541  			gl.bindBuffer( bufferType, attributeProperties.__webglBuffer );
 17542  
 17543  			if ( data.dynamic === false ) {
 17544  
 17545  				gl.bufferData( bufferType, data.array, gl.STATIC_DRAW );
 17546  
 17547  			} else if ( data.updateRange.count === - 1 ) {
 17548  
 17549  				// Not using update ranges
 17550  
 17551  				gl.bufferSubData( bufferType, 0, data.array );
 17552  
 17553  			} else if ( data.updateRange.count === 0 ) {
 17554  
 17555  				console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' );
 17556  
 17557  			} else {
 17558  
 17559  				gl.bufferSubData( bufferType, data.updateRange.offset * data.array.BYTES_PER_ELEMENT,
 17560  								  data.array.subarray( data.updateRange.offset, data.updateRange.offset + data.updateRange.count ) );
 17561  
 17562  				data.updateRange.count = 0; // reset range
 17563  
 17564  			}
 17565  
 17566  			attributeProperties.version = data.version;
 17567  
 17568  		}
 17569  
 17570  		function getAttributeBuffer( attribute ) {
 17571  
 17572  			if ( attribute.isInterleavedBufferAttribute ) {
 17573  
 17574  				return properties.get( attribute.data ).__webglBuffer;
 17575  
 17576  			}
 17577  
 17578  			return properties.get( attribute ).__webglBuffer;
 17579  
 17580  		}
 17581  
 17582  		function getAttributeProperties( attribute ) {
 17583  
 17584  			if ( attribute.isInterleavedBufferAttribute ) {
 17585  
 17586  				return properties.get( attribute.data );
 17587  
 17588  			}
 17589  
 17590  			return properties.get( attribute );
 17591  
 17592  		}
 17593  
 17594  		function getWireframeAttribute( geometry ) {
 17595  
 17596  			var property = properties.get( geometry );
 17597  
 17598  			if ( property.wireframe !== undefined ) {
 17599  
 17600  				return property.wireframe;
 17601  
 17602  			}
 17603  
 17604  			var indices = [];
 17605  
 17606  			var index = geometry.index;
 17607  			var attributes = geometry.attributes;
 17608  
 17609  			// console.time( 'wireframe' );
 17610  
 17611  			if ( index !== null ) {
 17612  
 17613  				var array = index.array;
 17614  
 17615  				for ( var i = 0, l = array.length; i < l; i += 3 ) {
 17616  
 17617  					var a = array[ i + 0 ];
 17618  					var b = array[ i + 1 ];
 17619  					var c = array[ i + 2 ];
 17620  
 17621  					indices.push( a, b, b, c, c, a );
 17622  
 17623  				}
 17624  
 17625  			} else {
 17626  
 17627  				var array = attributes.position.array;
 17628  
 17629  				for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
 17630  
 17631  					var a = i + 0;
 17632  					var b = i + 1;
 17633  					var c = i + 2;
 17634  
 17635  					indices.push( a, b, b, c, c, a );
 17636  
 17637  				}
 17638  
 17639  			}
 17640  
 17641  			// console.timeEnd( 'wireframe' );
 17642  
 17643  			var attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
 17644  
 17645  			updateAttribute( attribute, gl.ELEMENT_ARRAY_BUFFER );
 17646  
 17647  			property.wireframe = attribute;
 17648  
 17649  			return attribute;
 17650  
 17651  		}
 17652  
 17653  		return {
 17654  
 17655  			getAttributeBuffer: getAttributeBuffer,
 17656  			getAttributeProperties: getAttributeProperties,
 17657  			getWireframeAttribute: getWireframeAttribute,
 17658  
 17659  			update: update
 17660  
 17661  		};
 17662  
 17663  	}
 17664  
 17665  	/**
 17666  	 * @author mrdoob / http://mrdoob.com/
 17667  	 */
 17668  
 17669  	function WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, info ) {
 17670  
 17671  		var _infoMemory = info.memory;
 17672  		var _isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof WebGL2RenderingContext );
 17673  
 17674  		//
 17675  
 17676  		function clampToMaxSize( image, maxSize ) {
 17677  
 17678  			if ( image.width > maxSize || image.height > maxSize ) {
 17679  
 17680  				// Warning: Scaling through the canvas will only work with images that use
 17681  				// premultiplied alpha.
 17682  
 17683  				var scale = maxSize / Math.max( image.width, image.height );
 17684  
 17685  				var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
 17686  				canvas.width = Math.floor( image.width * scale );
 17687  				canvas.height = Math.floor( image.height * scale );
 17688  
 17689  				var context = canvas.getContext( '2d' );
 17690  				context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );
 17691  
 17692  				console.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );
 17693  
 17694  				return canvas;
 17695  
 17696  			}
 17697  
 17698  			return image;
 17699  
 17700  		}
 17701  
 17702  		function isPowerOfTwo( image ) {
 17703  
 17704  			return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height );
 17705  
 17706  		}
 17707  
 17708  		function makePowerOfTwo( image ) {
 17709  
 17710  			if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement ) {
 17711  
 17712  				var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
 17713  				canvas.width = _Math.nearestPowerOfTwo( image.width );
 17714  				canvas.height = _Math.nearestPowerOfTwo( image.height );
 17715  
 17716  				var context = canvas.getContext( '2d' );
 17717  				context.drawImage( image, 0, 0, canvas.width, canvas.height );
 17718  
 17719  				console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );
 17720  
 17721  				return canvas;
 17722  
 17723  			}
 17724  
 17725  			return image;
 17726  
 17727  		}
 17728  
 17729  		function textureNeedsPowerOfTwo( texture ) {
 17730  
 17731  			return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
 17732  				( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
 17733  
 17734  		}
 17735  
 17736  		// Fallback filters for non-power-of-2 textures
 17737  
 17738  		function filterFallback( f ) {
 17739  
 17740  			if ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) {
 17741  
 17742  				return _gl.NEAREST;
 17743  
 17744  			}
 17745  
 17746  			return _gl.LINEAR;
 17747  
 17748  		}
 17749  
 17750  		//
 17751  
 17752  		function onTextureDispose( event ) {
 17753  
 17754  			var texture = event.target;
 17755  
 17756  			texture.removeEventListener( 'dispose', onTextureDispose );
 17757  
 17758  			deallocateTexture( texture );
 17759  
 17760  			_infoMemory.textures --;
 17761  
 17762  
 17763  		}
 17764  
 17765  		function onRenderTargetDispose( event ) {
 17766  
 17767  			var renderTarget = event.target;
 17768  
 17769  			renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
 17770  
 17771  			deallocateRenderTarget( renderTarget );
 17772  
 17773  			_infoMemory.textures --;
 17774  
 17775  		}
 17776  
 17777  		//
 17778  
 17779  		function deallocateTexture( texture ) {
 17780  
 17781  			var textureProperties = properties.get( texture );
 17782  
 17783  			if ( texture.image && textureProperties.__image__webglTextureCube ) {
 17784  
 17785  				// cube texture
 17786  
 17787  				_gl.deleteTexture( textureProperties.__image__webglTextureCube );
 17788  
 17789  			} else {
 17790  
 17791  				// 2D texture
 17792  
 17793  				if ( textureProperties.__webglInit === undefined ) return;
 17794  
 17795  				_gl.deleteTexture( textureProperties.__webglTexture );
 17796  
 17797  			}
 17798  
 17799  			// remove all webgl properties
 17800  			properties.delete( texture );
 17801  
 17802  		}
 17803  
 17804  		function deallocateRenderTarget( renderTarget ) {
 17805  
 17806  			var renderTargetProperties = properties.get( renderTarget );
 17807  			var textureProperties = properties.get( renderTarget.texture );
 17808  
 17809  			if ( ! renderTarget ) return;
 17810  
 17811  			if ( textureProperties.__webglTexture !== undefined ) {
 17812  
 17813  				_gl.deleteTexture( textureProperties.__webglTexture );
 17814  
 17815  			}
 17816  
 17817  			if ( renderTarget.depthTexture ) {
 17818  
 17819  				renderTarget.depthTexture.dispose();
 17820  
 17821  			}
 17822  
 17823  			if ( renderTarget.isWebGLRenderTargetCube ) {
 17824  
 17825  				for ( var i = 0; i < 6; i ++ ) {
 17826  
 17827  					_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
 17828  					if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
 17829  
 17830  				}
 17831  
 17832  			} else {
 17833  
 17834  				_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
 17835  				if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
 17836  
 17837  			}
 17838  
 17839  			properties.delete( renderTarget.texture );
 17840  			properties.delete( renderTarget );
 17841  
 17842  		}
 17843  
 17844  		//
 17845  
 17846  
 17847  
 17848  		function setTexture2D( texture, slot ) {
 17849  
 17850  			var textureProperties = properties.get( texture );
 17851  
 17852  			if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
 17853  
 17854  				var image = texture.image;
 17855  
 17856  				if ( image === undefined ) {
 17857  
 17858  					console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined', texture );
 17859  
 17860  				} else if ( image.complete === false ) {
 17861  
 17862  					console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture );
 17863  
 17864  				} else {
 17865  
 17866  					uploadTexture( textureProperties, texture, slot );
 17867  					return;
 17868  
 17869  				}
 17870  
 17871  			}
 17872  
 17873  			state.activeTexture( _gl.TEXTURE0 + slot );
 17874  			state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
 17875  
 17876  		}
 17877  
 17878  		function setTextureCube( texture, slot ) {
 17879  
 17880  			var textureProperties = properties.get( texture );
 17881  
 17882  			if ( texture.image.length === 6 ) {
 17883  
 17884  				if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
 17885  
 17886  					if ( ! textureProperties.__image__webglTextureCube ) {
 17887  
 17888  						texture.addEventListener( 'dispose', onTextureDispose );
 17889  
 17890  						textureProperties.__image__webglTextureCube = _gl.createTexture();
 17891  
 17892  						_infoMemory.textures ++;
 17893  
 17894  					}
 17895  
 17896  					state.activeTexture( _gl.TEXTURE0 + slot );
 17897  					state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );
 17898  
 17899  					_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
 17900  
 17901  					var isCompressed = ( texture && texture.isCompressedTexture );
 17902  					var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
 17903  
 17904  					var cubeImage = [];
 17905  
 17906  					for ( var i = 0; i < 6; i ++ ) {
 17907  
 17908  						if ( ! isCompressed && ! isDataTexture ) {
 17909  
 17910  							cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize );
 17911  
 17912  						} else {
 17913  
 17914  							cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
 17915  
 17916  						}
 17917  
 17918  					}
 17919  
 17920  					var image = cubeImage[ 0 ],
 17921  					isPowerOfTwoImage = isPowerOfTwo( image ),
 17922  					glFormat = paramThreeToGL( texture.format ),
 17923  					glType = paramThreeToGL( texture.type );
 17924  
 17925  					setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isPowerOfTwoImage );
 17926  
 17927  					for ( var i = 0; i < 6; i ++ ) {
 17928  
 17929  						if ( ! isCompressed ) {
 17930  
 17931  							if ( isDataTexture ) {
 17932  
 17933  								state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
 17934  
 17935  							} else {
 17936  
 17937  								state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
 17938  
 17939  							}
 17940  
 17941  						} else {
 17942  
 17943  							var mipmap, mipmaps = cubeImage[ i ].mipmaps;
 17944  
 17945  							for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
 17946  
 17947  								mipmap = mipmaps[ j ];
 17948  
 17949  								if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
 17950  
 17951  									if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {
 17952  
 17953  										state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
 17954  
 17955  									} else {
 17956  
 17957  										console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()" );
 17958  
 17959  									}
 17960  
 17961  								} else {
 17962  
 17963  									state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
 17964  
 17965  								}
 17966  
 17967  							}
 17968  
 17969  						}
 17970  
 17971  					}
 17972  
 17973  					if ( texture.generateMipmaps && isPowerOfTwoImage ) {
 17974  
 17975  						_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
 17976  
 17977  					}
 17978  
 17979  					textureProperties.__version = texture.version;
 17980  
 17981  					if ( texture.onUpdate ) texture.onUpdate( texture );
 17982  
 17983  				} else {
 17984  
 17985  					state.activeTexture( _gl.TEXTURE0 + slot );
 17986  					state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );
 17987  
 17988  				}
 17989  
 17990  			}
 17991  
 17992  		}
 17993  
 17994  		function setTextureCubeDynamic( texture, slot ) {
 17995  
 17996  			state.activeTexture( _gl.TEXTURE0 + slot );
 17997  			state.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture );
 17998  
 17999  		}
 18000  
 18001  		function setTextureParameters( textureType, texture, isPowerOfTwoImage ) {
 18002  
 18003  			var extension;
 18004  
 18005  			if ( isPowerOfTwoImage ) {
 18006  
 18007  				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
 18008  				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );
 18009  
 18010  				_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );
 18011  				_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );
 18012  
 18013  			} else {
 18014  
 18015  				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
 18016  				_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
 18017  
 18018  				if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
 18019  
 18020  					console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.', texture );
 18021  
 18022  				}
 18023  
 18024  				_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
 18025  				_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
 18026  
 18027  				if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
 18028  
 18029  					console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.', texture );
 18030  
 18031  				}
 18032  
 18033  			}
 18034  
 18035  			extension = extensions.get( 'EXT_texture_filter_anisotropic' );
 18036  
 18037  			if ( extension ) {
 18038  
 18039  				if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return;
 18040  				if ( texture.type === HalfFloatType && extensions.get( 'OES_texture_half_float_linear' ) === null ) return;
 18041  
 18042  				if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
 18043  
 18044  					_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
 18045  					properties.get( texture ).__currentAnisotropy = texture.anisotropy;
 18046  
 18047  				}
 18048  
 18049  			}
 18050  
 18051  		}
 18052  
 18053  		function uploadTexture( textureProperties, texture, slot ) {
 18054  
 18055  			if ( textureProperties.__webglInit === undefined ) {
 18056  
 18057  				textureProperties.__webglInit = true;
 18058  
 18059  				texture.addEventListener( 'dispose', onTextureDispose );
 18060  
 18061  				textureProperties.__webglTexture = _gl.createTexture();
 18062  
 18063  				_infoMemory.textures ++;
 18064  
 18065  			}
 18066  
 18067  			state.activeTexture( _gl.TEXTURE0 + slot );
 18068  			state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
 18069  
 18070  			_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
 18071  			_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
 18072  			_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
 18073  
 18074  			var image = clampToMaxSize( texture.image, capabilities.maxTextureSize );
 18075  
 18076  			if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) {
 18077  
 18078  				image = makePowerOfTwo( image );
 18079  
 18080  			}
 18081  
 18082  			var isPowerOfTwoImage = isPowerOfTwo( image ),
 18083  			glFormat = paramThreeToGL( texture.format ),
 18084  			glType = paramThreeToGL( texture.type );
 18085  
 18086  			setTextureParameters( _gl.TEXTURE_2D, texture, isPowerOfTwoImage );
 18087  
 18088  			var mipmap, mipmaps = texture.mipmaps;
 18089  
 18090  			if ( texture.isDepthTexture ) {
 18091  
 18092  				// populate depth texture with dummy data
 18093  
 18094  				var internalFormat = _gl.DEPTH_COMPONENT;
 18095  
 18096  				if ( texture.type === FloatType ) {
 18097  
 18098  					if ( !_isWebGL2 ) throw new Error('Float Depth Texture only supported in WebGL2.0');
 18099  					internalFormat = _gl.DEPTH_COMPONENT32F;
 18100  
 18101  				} else if ( _isWebGL2 ) {
 18102  
 18103  					// WebGL 2.0 requires signed internalformat for glTexImage2D
 18104  					internalFormat = _gl.DEPTH_COMPONENT16;
 18105  
 18106  				}
 18107  
 18108  				if ( texture.format === DepthFormat && internalFormat === _gl.DEPTH_COMPONENT ) {
 18109  
 18110  					// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
 18111  					// DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
 18112  					// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
 18113  					if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
 18114  
 18115  					        console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
 18116  
 18117  						texture.type = UnsignedShortType;
 18118  						glType = paramThreeToGL( texture.type );
 18119  
 18120  					}
 18121  
 18122  				}
 18123  
 18124  				// Depth stencil textures need the DEPTH_STENCIL internal format
 18125  				// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
 18126  				if ( texture.format === DepthStencilFormat ) {
 18127  
 18128  					internalFormat = _gl.DEPTH_STENCIL;
 18129  
 18130  					// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
 18131  					// DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
 18132  					// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
 18133  					if ( texture.type !== UnsignedInt248Type ) {
 18134  
 18135  					        console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
 18136  
 18137  						texture.type = UnsignedInt248Type;
 18138  						glType = paramThreeToGL( texture.type );
 18139  
 18140  					}
 18141  
 18142  				}
 18143  
 18144  				state.texImage2D( _gl.TEXTURE_2D, 0, internalFormat, image.width, image.height, 0, glFormat, glType, null );
 18145  
 18146  			} else if ( texture.isDataTexture ) {
 18147  
 18148  				// use manually created mipmaps if available
 18149  				// if there are no manual mipmaps
 18150  				// set 0 level mipmap and then use GL to generate other mipmap levels
 18151  
 18152  				if ( mipmaps.length > 0 && isPowerOfTwoImage ) {
 18153  
 18154  					for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
 18155  
 18156  						mipmap = mipmaps[ i ];
 18157  						state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
 18158  
 18159  					}
 18160  
 18161  					texture.generateMipmaps = false;
 18162  
 18163  				} else {
 18164  
 18165  					state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
 18166  
 18167  				}
 18168  
 18169  			} else if ( texture.isCompressedTexture ) {
 18170  
 18171  				for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
 18172  
 18173  					mipmap = mipmaps[ i ];
 18174  
 18175  					if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
 18176  
 18177  						if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {
 18178  
 18179  							state.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
 18180  
 18181  						} else {
 18182  
 18183  							console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" );
 18184  
 18185  						}
 18186  
 18187  					} else {
 18188  
 18189  						state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
 18190  
 18191  					}
 18192  
 18193  				}
 18194  
 18195  			} else {
 18196  
 18197  				// regular Texture (image, video, canvas)
 18198  
 18199  				// use manually created mipmaps if available
 18200  				// if there are no manual mipmaps
 18201  				// set 0 level mipmap and then use GL to generate other mipmap levels
 18202  
 18203  				if ( mipmaps.length > 0 && isPowerOfTwoImage ) {
 18204  
 18205  					for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
 18206  
 18207  						mipmap = mipmaps[ i ];
 18208  						state.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
 18209  
 18210  					}
 18211  
 18212  					texture.generateMipmaps = false;
 18213  
 18214  				} else {
 18215  
 18216  					state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, image );
 18217  
 18218  				}
 18219  
 18220  			}
 18221  
 18222  			if ( texture.generateMipmaps && isPowerOfTwoImage ) _gl.generateMipmap( _gl.TEXTURE_2D );
 18223  
 18224  			textureProperties.__version = texture.version;
 18225  
 18226  			if ( texture.onUpdate ) texture.onUpdate( texture );
 18227  
 18228  		}
 18229  
 18230  		// Render targets
 18231  
 18232  		// Setup storage for target texture and bind it to correct framebuffer
 18233  		function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) {
 18234  
 18235  			var glFormat = paramThreeToGL( renderTarget.texture.format );
 18236  			var glType = paramThreeToGL( renderTarget.texture.type );
 18237  			state.texImage2D( textureTarget, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
 18238  			_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
 18239  			_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );
 18240  			_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
 18241  
 18242  		}
 18243  
 18244  		// Setup storage for internal depth/stencil buffers and bind to correct framebuffer
 18245  		function setupRenderBufferStorage( renderbuffer, renderTarget ) {
 18246  
 18247  			_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
 18248  
 18249  			if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
 18250  
 18251  				_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
 18252  				_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
 18253  
 18254  			} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
 18255  
 18256  				_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
 18257  				_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
 18258  
 18259  			} else {
 18260  
 18261  				// FIXME: We don't support !depth !stencil
 18262  				_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
 18263  
 18264  			}
 18265  
 18266  			_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
 18267  
 18268  		}
 18269  
 18270  		// Setup resources for a Depth Texture for a FBO (needs an extension)
 18271  		function setupDepthTexture( framebuffer, renderTarget ) {
 18272  
 18273  			var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube );
 18274  			if ( isCube ) throw new Error('Depth Texture with cube render targets is not supported!');
 18275  
 18276  			_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
 18277  
 18278  			if ( !( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
 18279  
 18280  				throw new Error('renderTarget.depthTexture must be an instance of THREE.DepthTexture');
 18281  
 18282  			}
 18283  
 18284  			// upload an empty depth texture with framebuffer size
 18285  			if ( !properties.get( renderTarget.depthTexture ).__webglTexture ||
 18286  					renderTarget.depthTexture.image.width !== renderTarget.width ||
 18287  					renderTarget.depthTexture.image.height !== renderTarget.height ) {
 18288  				renderTarget.depthTexture.image.width = renderTarget.width;
 18289  				renderTarget.depthTexture.image.height = renderTarget.height;
 18290  				renderTarget.depthTexture.needsUpdate = true;
 18291  			}
 18292  
 18293  			setTexture2D( renderTarget.depthTexture, 0 );
 18294  
 18295  			var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
 18296  
 18297  			if ( renderTarget.depthTexture.format === DepthFormat ) {
 18298  
 18299  				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
 18300  
 18301  			} else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
 18302  
 18303  				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
 18304  
 18305  			} else {
 18306  
 18307  				throw new Error('Unknown depthTexture format')
 18308  
 18309  			}
 18310  
 18311  		}
 18312  
 18313  		// Setup GL resources for a non-texture depth buffer
 18314  		function setupDepthRenderbuffer( renderTarget ) {
 18315  
 18316  			var renderTargetProperties = properties.get( renderTarget );
 18317  
 18318  			var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
 18319  
 18320  			if ( renderTarget.depthTexture ) {
 18321  
 18322  				if ( isCube ) throw new Error('target.depthTexture not supported in Cube render targets');
 18323  
 18324  				setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );
 18325  
 18326  			} else {
 18327  
 18328  				if ( isCube ) {
 18329  
 18330  					renderTargetProperties.__webglDepthbuffer = [];
 18331  
 18332  					for ( var i = 0; i < 6; i ++ ) {
 18333  
 18334  						_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );
 18335  						renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
 18336  						setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget );
 18337  
 18338  					}
 18339  
 18340  				} else {
 18341  
 18342  					_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
 18343  					renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
 18344  					setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget );
 18345  
 18346  				}
 18347  
 18348  			}
 18349  
 18350  			_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
 18351  
 18352  		}
 18353  
 18354  		// Set up GL resources for the render target
 18355  		function setupRenderTarget( renderTarget ) {
 18356  
 18357  			var renderTargetProperties = properties.get( renderTarget );
 18358  			var textureProperties = properties.get( renderTarget.texture );
 18359  
 18360  			renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
 18361  
 18362  			textureProperties.__webglTexture = _gl.createTexture();
 18363  
 18364  			_infoMemory.textures ++;
 18365  
 18366  			var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
 18367  			var isTargetPowerOfTwo = isPowerOfTwo( renderTarget );
 18368  
 18369  			// Setup framebuffer
 18370  
 18371  			if ( isCube ) {
 18372  
 18373  				renderTargetProperties.__webglFramebuffer = [];
 18374  
 18375  				for ( var i = 0; i < 6; i ++ ) {
 18376  
 18377  					renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
 18378  
 18379  				}
 18380  
 18381  			} else {
 18382  
 18383  				renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
 18384  
 18385  			}
 18386  
 18387  			// Setup color buffer
 18388  
 18389  			if ( isCube ) {
 18390  
 18391  				state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
 18392  				setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo );
 18393  
 18394  				for ( var i = 0; i < 6; i ++ ) {
 18395  
 18396  					setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
 18397  
 18398  				}
 18399  
 18400  				if ( renderTarget.texture.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
 18401  				state.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
 18402  
 18403  			} else {
 18404  
 18405  				state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
 18406  				setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo );
 18407  				setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D );
 18408  
 18409  				if ( renderTarget.texture.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
 18410  				state.bindTexture( _gl.TEXTURE_2D, null );
 18411  
 18412  			}
 18413  
 18414  			// Setup depth and stencil buffers
 18415  
 18416  			if ( renderTarget.depthBuffer ) {
 18417  
 18418  				setupDepthRenderbuffer( renderTarget );
 18419  
 18420  			}
 18421  
 18422  		}
 18423  
 18424  		function updateRenderTargetMipmap( renderTarget ) {
 18425  
 18426  			var texture = renderTarget.texture;
 18427  
 18428  			if ( texture.generateMipmaps && isPowerOfTwo( renderTarget ) &&
 18429  					texture.minFilter !== NearestFilter &&
 18430  					texture.minFilter !== LinearFilter ) {
 18431  
 18432  				var target = (renderTarget && renderTarget.isWebGLRenderTargetCube) ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;
 18433  				var webglTexture = properties.get( texture ).__webglTexture;
 18434  
 18435  				state.bindTexture( target, webglTexture );
 18436  				_gl.generateMipmap( target );
 18437  				state.bindTexture( target, null );
 18438  
 18439  			}
 18440  
 18441  		}
 18442  
 18443  		this.setTexture2D = setTexture2D;
 18444  		this.setTextureCube = setTextureCube;
 18445  		this.setTextureCubeDynamic = setTextureCubeDynamic;
 18446  		this.setupRenderTarget = setupRenderTarget;
 18447  		this.updateRenderTargetMipmap = updateRenderTargetMipmap;
 18448  
 18449  	}
 18450  
 18451  	/**
 18452  	 * @author fordacious / fordacious.github.io
 18453  	 */
 18454  
 18455  	function WebGLProperties() {
 18456  
 18457  		var properties = {};
 18458  
 18459  		return {
 18460  
 18461  			get: function ( object ) {
 18462  
 18463  				var uuid = object.uuid;
 18464  				var map = properties[ uuid ];
 18465  
 18466  				if ( map === undefined ) {
 18467  
 18468  					map = {};
 18469  					properties[ uuid ] = map;
 18470  
 18471  				}
 18472  
 18473  				return map;
 18474  
 18475  			},
 18476  
 18477  			delete: function ( object ) {
 18478  
 18479  				delete properties[ object.uuid ];
 18480  
 18481  			},
 18482  
 18483  			clear: function () {
 18484  
 18485  				properties = {};
 18486  
 18487  			}
 18488  
 18489  		};
 18490  
 18491  	}
 18492  
 18493  	/**
 18494  	 * @author mrdoob / http://mrdoob.com/
 18495  	 */
 18496  
 18497  	function WebGLState( gl, extensions, paramThreeToGL ) {
 18498  
 18499  		function ColorBuffer() {
 18500  
 18501  			var locked = false;
 18502  
 18503  			var color = new Vector4();
 18504  			var currentColorMask = null;
 18505  			var currentColorClear = new Vector4();
 18506  
 18507  			return {
 18508  
 18509  				setMask: function ( colorMask ) {
 18510  
 18511  					if ( currentColorMask !== colorMask && ! locked ) {
 18512  
 18513  						gl.colorMask( colorMask, colorMask, colorMask, colorMask );
 18514  						currentColorMask = colorMask;
 18515  
 18516  					}
 18517  
 18518  				},
 18519  
 18520  				setLocked: function ( lock ) {
 18521  
 18522  					locked = lock;
 18523  
 18524  				},
 18525  
 18526  				setClear: function ( r, g, b, a, premultipliedAlpha ) {
 18527  
 18528  					if ( premultipliedAlpha === true ) {
 18529  
 18530  						r *= a; g *= a; b *= a;
 18531  
 18532  					}
 18533  
 18534  					color.set( r, g, b, a );
 18535  
 18536  					if ( currentColorClear.equals( color ) === false ) {
 18537  
 18538  						gl.clearColor( r, g, b, a );
 18539  						currentColorClear.copy( color );
 18540  
 18541  					}
 18542  
 18543  				},
 18544  
 18545  				reset: function () {
 18546  
 18547  					locked = false;
 18548  
 18549  					currentColorMask = null;
 18550  					currentColorClear.set( 0, 0, 0, 1 );
 18551  
 18552  				}
 18553  
 18554  			};
 18555  
 18556  		}
 18557  
 18558  		function DepthBuffer() {
 18559  
 18560  			var locked = false;
 18561  
 18562  			var currentDepthMask = null;
 18563  			var currentDepthFunc = null;
 18564  			var currentDepthClear = null;
 18565  
 18566  			return {
 18567  
 18568  				setTest: function ( depthTest ) {
 18569  
 18570  					if ( depthTest ) {
 18571  
 18572  						enable( gl.DEPTH_TEST );
 18573  
 18574  					} else {
 18575  
 18576  						disable( gl.DEPTH_TEST );
 18577  
 18578  					}
 18579  
 18580  				},
 18581  
 18582  				setMask: function ( depthMask ) {
 18583  
 18584  					if ( currentDepthMask !== depthMask && ! locked ) {
 18585  
 18586  						gl.depthMask( depthMask );
 18587  						currentDepthMask = depthMask;
 18588  
 18589  					}
 18590  
 18591  				},
 18592  
 18593  				setFunc: function ( depthFunc ) {
 18594  
 18595  					if ( currentDepthFunc !== depthFunc ) {
 18596  
 18597  						if ( depthFunc ) {
 18598  
 18599  							switch ( depthFunc ) {
 18600  
 18601  								case NeverDepth:
 18602  
 18603  									gl.depthFunc( gl.NEVER );
 18604  									break;
 18605  
 18606  								case AlwaysDepth:
 18607  
 18608  									gl.depthFunc( gl.ALWAYS );
 18609  									break;
 18610  
 18611  								case LessDepth:
 18612  
 18613  									gl.depthFunc( gl.LESS );
 18614  									break;
 18615  
 18616  								case LessEqualDepth:
 18617  
 18618  									gl.depthFunc( gl.LEQUAL );
 18619  									break;
 18620  
 18621  								case EqualDepth:
 18622  
 18623  									gl.depthFunc( gl.EQUAL );
 18624  									break;
 18625  
 18626  								case GreaterEqualDepth:
 18627  
 18628  									gl.depthFunc( gl.GEQUAL );
 18629  									break;
 18630  
 18631  								case GreaterDepth:
 18632  
 18633  									gl.depthFunc( gl.GREATER );
 18634  									break;
 18635  
 18636  								case NotEqualDepth:
 18637  
 18638  									gl.depthFunc( gl.NOTEQUAL );
 18639  									break;
 18640  
 18641  								default:
 18642  
 18643  									gl.depthFunc( gl.LEQUAL );
 18644  
 18645  							}
 18646  
 18647  						} else {
 18648  
 18649  							gl.depthFunc( gl.LEQUAL );
 18650  
 18651  						}
 18652  
 18653  						currentDepthFunc = depthFunc;
 18654  
 18655  					}
 18656  
 18657  				},
 18658  
 18659  				setLocked: function ( lock ) {
 18660  
 18661  					locked = lock;
 18662  
 18663  				},
 18664  
 18665  				setClear: function ( depth ) {
 18666  
 18667  					if ( currentDepthClear !== depth ) {
 18668  
 18669  						gl.clearDepth( depth );
 18670  						currentDepthClear = depth;
 18671  
 18672  					}
 18673  
 18674  				},
 18675  
 18676  				reset: function () {
 18677  
 18678  					locked = false;
 18679  
 18680  					currentDepthMask = null;
 18681  					currentDepthFunc = null;
 18682  					currentDepthClear = null;
 18683  
 18684  				}
 18685  
 18686  			};
 18687  
 18688  		}
 18689  
 18690  		function StencilBuffer() {
 18691  
 18692  			var locked = false;
 18693  
 18694  			var currentStencilMask = null;
 18695  			var currentStencilFunc = null;
 18696  			var currentStencilRef = null;
 18697  			var currentStencilFuncMask = null;
 18698  			var currentStencilFail = null;
 18699  			var currentStencilZFail = null;
 18700  			var currentStencilZPass = null;
 18701  			var currentStencilClear = null;
 18702  
 18703  			return {
 18704  
 18705  				setTest: function ( stencilTest ) {
 18706  
 18707  					if ( stencilTest ) {
 18708  
 18709  						enable( gl.STENCIL_TEST );
 18710  
 18711  					} else {
 18712  
 18713  						disable( gl.STENCIL_TEST );
 18714  
 18715  					}
 18716  
 18717  				},
 18718  
 18719  				setMask: function ( stencilMask ) {
 18720  
 18721  					if ( currentStencilMask !== stencilMask && ! locked ) {
 18722  
 18723  						gl.stencilMask( stencilMask );
 18724  						currentStencilMask = stencilMask;
 18725  
 18726  					}
 18727  
 18728  				},
 18729  
 18730  				setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
 18731  
 18732  					if ( currentStencilFunc !== stencilFunc ||
 18733  					     currentStencilRef 	!== stencilRef 	||
 18734  					     currentStencilFuncMask !== stencilMask ) {
 18735  
 18736  						gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
 18737  
 18738  						currentStencilFunc = stencilFunc;
 18739  						currentStencilRef = stencilRef;
 18740  						currentStencilFuncMask = stencilMask;
 18741  
 18742  					}
 18743  
 18744  				},
 18745  
 18746  				setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
 18747  
 18748  					if ( currentStencilFail	 !== stencilFail 	||
 18749  					     currentStencilZFail !== stencilZFail ||
 18750  					     currentStencilZPass !== stencilZPass ) {
 18751  
 18752  						gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
 18753  
 18754  						currentStencilFail = stencilFail;
 18755  						currentStencilZFail = stencilZFail;
 18756  						currentStencilZPass = stencilZPass;
 18757  
 18758  					}
 18759  
 18760  				},
 18761  
 18762  				setLocked: function ( lock ) {
 18763  
 18764  					locked = lock;
 18765  
 18766  				},
 18767  
 18768  				setClear: function ( stencil ) {
 18769  
 18770  					if ( currentStencilClear !== stencil ) {
 18771  
 18772  						gl.clearStencil( stencil );
 18773  						currentStencilClear = stencil;
 18774  
 18775  					}
 18776  
 18777  				},
 18778  
 18779  				reset: function () {
 18780  
 18781  					locked = false;
 18782  
 18783  					currentStencilMask = null;
 18784  					currentStencilFunc = null;
 18785  					currentStencilRef = null;
 18786  					currentStencilFuncMask = null;
 18787  					currentStencilFail = null;
 18788  					currentStencilZFail = null;
 18789  					currentStencilZPass = null;
 18790  					currentStencilClear = null;
 18791  
 18792  				}
 18793  
 18794  			};
 18795  
 18796  		}
 18797  
 18798  		//
 18799  
 18800  		var colorBuffer = new ColorBuffer();
 18801  		var depthBuffer = new DepthBuffer();
 18802  		var stencilBuffer = new StencilBuffer();
 18803  
 18804  		var maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
 18805  		var newAttributes = new Uint8Array( maxVertexAttributes );
 18806  		var enabledAttributes = new Uint8Array( maxVertexAttributes );
 18807  		var attributeDivisors = new Uint8Array( maxVertexAttributes );
 18808  
 18809  		var capabilities = {};
 18810  
 18811  		var compressedTextureFormats = null;
 18812  
 18813  		var currentBlending = null;
 18814  		var currentBlendEquation = null;
 18815  		var currentBlendSrc = null;
 18816  		var currentBlendDst = null;
 18817  		var currentBlendEquationAlpha = null;
 18818  		var currentBlendSrcAlpha = null;
 18819  		var currentBlendDstAlpha = null;
 18820  		var currentPremultipledAlpha = false;
 18821  
 18822  		var currentFlipSided = null;
 18823  		var currentCullFace = null;
 18824  
 18825  		var currentLineWidth = null;
 18826  
 18827  		var currentPolygonOffsetFactor = null;
 18828  		var currentPolygonOffsetUnits = null;
 18829  
 18830  		var currentScissorTest = null;
 18831  
 18832  		var maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );
 18833  
 18834  		var version = parseFloat( /^WebGL\ ([0-9])/.exec( gl.getParameter( gl.VERSION ) )[ 1 ] );
 18835  		var lineWidthAvailable = parseFloat( version ) >= 1.0;
 18836  
 18837  		var currentTextureSlot = null;
 18838  		var currentBoundTextures = {};
 18839  
 18840  		var currentScissor = new Vector4();
 18841  		var currentViewport = new Vector4();
 18842  
 18843  		function createTexture( type, target, count ) {
 18844  
 18845  			var data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
 18846  			var texture = gl.createTexture();
 18847  
 18848  			gl.bindTexture( type, texture );
 18849  			gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
 18850  			gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
 18851  
 18852  			for ( var i = 0; i < count; i ++ ) {
 18853  
 18854  				gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
 18855  
 18856  			}
 18857  
 18858  			return texture;
 18859  
 18860  		}
 18861  
 18862  		var emptyTextures = {};
 18863  		emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );
 18864  		emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );
 18865  
 18866  		//
 18867  
 18868  		function init() {
 18869  
 18870  			colorBuffer.setClear( 0, 0, 0, 1 );
 18871  			depthBuffer.setClear( 1 );
 18872  			stencilBuffer.setClear( 0 );
 18873  
 18874  			enable( gl.DEPTH_TEST );
 18875  			setDepthFunc( LessEqualDepth );
 18876  
 18877  			setFlipSided( false );
 18878  			setCullFace( CullFaceBack );
 18879  			enable( gl.CULL_FACE );
 18880  
 18881  			enable( gl.BLEND );
 18882  			setBlending( NormalBlending );
 18883  
 18884  		}
 18885  
 18886  		function initAttributes() {
 18887  
 18888  			for ( var i = 0, l = newAttributes.length; i < l; i ++ ) {
 18889  
 18890  				newAttributes[ i ] = 0;
 18891  
 18892  			}
 18893  
 18894  		}
 18895  
 18896  		function enableAttribute( attribute ) {
 18897  
 18898  			newAttributes[ attribute ] = 1;
 18899  
 18900  			if ( enabledAttributes[ attribute ] === 0 ) {
 18901  
 18902  				gl.enableVertexAttribArray( attribute );
 18903  				enabledAttributes[ attribute ] = 1;
 18904  
 18905  			}
 18906  
 18907  			if ( attributeDivisors[ attribute ] !== 0 ) {
 18908  
 18909  				var extension = extensions.get( 'ANGLE_instanced_arrays' );
 18910  
 18911  				extension.vertexAttribDivisorANGLE( attribute, 0 );
 18912  				attributeDivisors[ attribute ] = 0;
 18913  
 18914  			}
 18915  
 18916  		}
 18917  
 18918  		function enableAttributeAndDivisor( attribute, meshPerAttribute, extension ) {
 18919  
 18920  			newAttributes[ attribute ] = 1;
 18921  
 18922  			if ( enabledAttributes[ attribute ] === 0 ) {
 18923  
 18924  				gl.enableVertexAttribArray( attribute );
 18925  				enabledAttributes[ attribute ] = 1;
 18926  
 18927  			}
 18928  
 18929  			if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {
 18930  
 18931  				extension.vertexAttribDivisorANGLE( attribute, meshPerAttribute );
 18932  				attributeDivisors[ attribute ] = meshPerAttribute;
 18933  
 18934  			}
 18935  
 18936  		}
 18937  
 18938  		function disableUnusedAttributes() {
 18939  
 18940  			for ( var i = 0, l = enabledAttributes.length; i !== l; ++ i ) {
 18941  
 18942  				if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {
 18943  
 18944  					gl.disableVertexAttribArray( i );
 18945  					enabledAttributes[ i ] = 0;
 18946  
 18947  				}
 18948  
 18949  			}
 18950  
 18951  		}
 18952  
 18953  		function enable( id ) {
 18954  
 18955  			if ( capabilities[ id ] !== true ) {
 18956  
 18957  				gl.enable( id );
 18958  				capabilities[ id ] = true;
 18959  
 18960  			}
 18961  
 18962  		}
 18963  
 18964  		function disable( id ) {
 18965  
 18966  			if ( capabilities[ id ] !== false ) {
 18967  
 18968  				gl.disable( id );
 18969  				capabilities[ id ] = false;
 18970  
 18971  			}
 18972  
 18973  		}
 18974  
 18975  		function getCompressedTextureFormats() {
 18976  
 18977  			if ( compressedTextureFormats === null ) {
 18978  
 18979  				compressedTextureFormats = [];
 18980  
 18981  				if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) ||
 18982  				     extensions.get( 'WEBGL_compressed_texture_s3tc' ) ||
 18983  				     extensions.get( 'WEBGL_compressed_texture_etc1' ) ) {
 18984  
 18985  					var formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS );
 18986  
 18987  					for ( var i = 0; i < formats.length; i ++ ) {
 18988  
 18989  						compressedTextureFormats.push( formats[ i ] );
 18990  
 18991  					}
 18992  
 18993  				}
 18994  
 18995  			}
 18996  
 18997  			return compressedTextureFormats;
 18998  
 18999  		}
 19000  
 19001  		function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
 19002  
 19003  			if ( blending !== NoBlending ) {
 19004  
 19005  				enable( gl.BLEND );
 19006  
 19007  			} else {
 19008  
 19009  				disable( gl.BLEND );
 19010  
 19011  			}
 19012  
 19013  			if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {
 19014  
 19015  				if ( blending === AdditiveBlending ) {
 19016  
 19017  					if ( premultipliedAlpha ) {
 19018  
 19019  						gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
 19020  						gl.blendFuncSeparate( gl.ONE, gl.ONE, gl.ONE, gl.ONE );
 19021  
 19022  					} else {
 19023  
 19024  						gl.blendEquation( gl.FUNC_ADD );
 19025  						gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
 19026  
 19027  					}
 19028  
 19029  				} else if ( blending === SubtractiveBlending ) {
 19030  
 19031  					if ( premultipliedAlpha ) {
 19032  
 19033  						gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
 19034  						gl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA );
 19035  
 19036  					} else {
 19037  
 19038  						gl.blendEquation( gl.FUNC_ADD );
 19039  						gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR );
 19040  
 19041  					}
 19042  
 19043  				} else if ( blending === MultiplyBlending ) {
 19044  
 19045  					if ( premultipliedAlpha ) {
 19046  
 19047  						gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
 19048  						gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
 19049  
 19050  					} else {
 19051  
 19052  						gl.blendEquation( gl.FUNC_ADD );
 19053  						gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
 19054  
 19055  					}
 19056  
 19057  				} else {
 19058  
 19059  					if ( premultipliedAlpha ) {
 19060  
 19061  						gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
 19062  						gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
 19063  
 19064  					} else {
 19065  
 19066  						gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
 19067  						gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
 19068  
 19069  					}
 19070  
 19071  				}
 19072  
 19073  				currentBlending = blending;
 19074  				currentPremultipledAlpha = premultipliedAlpha;
 19075  
 19076  			}
 19077  
 19078  			if ( blending === CustomBlending ) {
 19079  
 19080  				blendEquationAlpha = blendEquationAlpha || blendEquation;
 19081  				blendSrcAlpha = blendSrcAlpha || blendSrc;
 19082  				blendDstAlpha = blendDstAlpha || blendDst;
 19083  
 19084  				if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
 19085  
 19086  					gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) );
 19087  
 19088  					currentBlendEquation = blendEquation;
 19089  					currentBlendEquationAlpha = blendEquationAlpha;
 19090  
 19091  				}
 19092  
 19093  				if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
 19094  
 19095  					gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) );
 19096  
 19097  					currentBlendSrc = blendSrc;
 19098  					currentBlendDst = blendDst;
 19099  					currentBlendSrcAlpha = blendSrcAlpha;
 19100  					currentBlendDstAlpha = blendDstAlpha;
 19101  
 19102  				}
 19103  
 19104  			} else {
 19105  
 19106  				currentBlendEquation = null;
 19107  				currentBlendSrc = null;
 19108  				currentBlendDst = null;
 19109  				currentBlendEquationAlpha = null;
 19110  				currentBlendSrcAlpha = null;
 19111  				currentBlendDstAlpha = null;
 19112  
 19113  			}
 19114  
 19115  		}
 19116  
 19117  		// TODO Deprecate
 19118  
 19119  		function setColorWrite( colorWrite ) {
 19120  
 19121  			colorBuffer.setMask( colorWrite );
 19122  
 19123  		}
 19124  
 19125  		function setDepthTest( depthTest ) {
 19126  
 19127  			depthBuffer.setTest( depthTest );
 19128  
 19129  		}
 19130  
 19131  		function setDepthWrite( depthWrite ) {
 19132  
 19133  			depthBuffer.setMask( depthWrite );
 19134  
 19135  		}
 19136  
 19137  		function setDepthFunc( depthFunc ) {
 19138  
 19139  			depthBuffer.setFunc( depthFunc );
 19140  
 19141  		}
 19142  
 19143  		function setStencilTest( stencilTest ) {
 19144  
 19145  			stencilBuffer.setTest( stencilTest );
 19146  
 19147  		}
 19148  
 19149  		function setStencilWrite( stencilWrite ) {
 19150  
 19151  			stencilBuffer.setMask( stencilWrite );
 19152  
 19153  		}
 19154  
 19155  		function setStencilFunc( stencilFunc, stencilRef, stencilMask ) {
 19156  
 19157  			stencilBuffer.setFunc( stencilFunc, stencilRef, stencilMask );
 19158  
 19159  		}
 19160  
 19161  		function setStencilOp( stencilFail, stencilZFail, stencilZPass ) {
 19162  
 19163  			stencilBuffer.setOp( stencilFail, stencilZFail, stencilZPass );
 19164  
 19165  		}
 19166  
 19167  		//
 19168  
 19169  		function setFlipSided( flipSided ) {
 19170  
 19171  			if ( currentFlipSided !== flipSided ) {
 19172  
 19173  				if ( flipSided ) {
 19174  
 19175  					gl.frontFace( gl.CW );
 19176  
 19177  				} else {
 19178  
 19179  					gl.frontFace( gl.CCW );
 19180  
 19181  				}
 19182  
 19183  				currentFlipSided = flipSided;
 19184  
 19185  			}
 19186  
 19187  		}
 19188  
 19189  		function setCullFace( cullFace ) {
 19190  
 19191  			if ( cullFace !== CullFaceNone ) {
 19192  
 19193  				enable( gl.CULL_FACE );
 19194  
 19195  				if ( cullFace !== currentCullFace ) {
 19196  
 19197  					if ( cullFace === CullFaceBack ) {
 19198  
 19199  						gl.cullFace( gl.BACK );
 19200  
 19201  					} else if ( cullFace === CullFaceFront ) {
 19202  
 19203  						gl.cullFace( gl.FRONT );
 19204  
 19205  					} else {
 19206  
 19207  						gl.cullFace( gl.FRONT_AND_BACK );
 19208  
 19209  					}
 19210  
 19211  				}
 19212  
 19213  			} else {
 19214  
 19215  				disable( gl.CULL_FACE );
 19216  
 19217  			}
 19218  
 19219  			currentCullFace = cullFace;
 19220  
 19221  		}
 19222  
 19223  		function setLineWidth( width ) {
 19224  
 19225  			if ( width !== currentLineWidth ) {
 19226  
 19227  				if ( lineWidthAvailable ) gl.lineWidth( width );
 19228  
 19229  				currentLineWidth = width;
 19230  
 19231  			}
 19232  
 19233  		}
 19234  
 19235  		function setPolygonOffset( polygonOffset, factor, units ) {
 19236  
 19237  			if ( polygonOffset ) {
 19238  
 19239  				enable( gl.POLYGON_OFFSET_FILL );
 19240  
 19241  				if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {
 19242  
 19243  					gl.polygonOffset( factor, units );
 19244  
 19245  					currentPolygonOffsetFactor = factor;
 19246  					currentPolygonOffsetUnits = units;
 19247  
 19248  				}
 19249  
 19250  			} else {
 19251  
 19252  				disable( gl.POLYGON_OFFSET_FILL );
 19253  
 19254  			}
 19255  
 19256  		}
 19257  
 19258  		function getScissorTest() {
 19259  
 19260  			return currentScissorTest;
 19261  
 19262  		}
 19263  
 19264  		function setScissorTest( scissorTest ) {
 19265  
 19266  			currentScissorTest = scissorTest;
 19267  
 19268  			if ( scissorTest ) {
 19269  
 19270  				enable( gl.SCISSOR_TEST );
 19271  
 19272  			} else {
 19273  
 19274  				disable( gl.SCISSOR_TEST );
 19275  
 19276  			}
 19277  
 19278  		}
 19279  
 19280  		// texture
 19281  
 19282  		function activeTexture( webglSlot ) {
 19283  
 19284  			if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;
 19285  
 19286  			if ( currentTextureSlot !== webglSlot ) {
 19287  
 19288  				gl.activeTexture( webglSlot );
 19289  				currentTextureSlot = webglSlot;
 19290  
 19291  			}
 19292  
 19293  		}
 19294  
 19295  		function bindTexture( webglType, webglTexture ) {
 19296  
 19297  			if ( currentTextureSlot === null ) {
 19298  
 19299  				activeTexture();
 19300  
 19301  			}
 19302  
 19303  			var boundTexture = currentBoundTextures[ currentTextureSlot ];
 19304  
 19305  			if ( boundTexture === undefined ) {
 19306  
 19307  				boundTexture = { type: undefined, texture: undefined };
 19308  				currentBoundTextures[ currentTextureSlot ] = boundTexture;
 19309  
 19310  			}
 19311  
 19312  			if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
 19313  
 19314  				gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
 19315  
 19316  				boundTexture.type = webglType;
 19317  				boundTexture.texture = webglTexture;
 19318  
 19319  			}
 19320  
 19321  		}
 19322  
 19323  		function compressedTexImage2D() {
 19324  
 19325  			try {
 19326  
 19327  				gl.compressedTexImage2D.apply( gl, arguments );
 19328  
 19329  			} catch ( error ) {
 19330  
 19331  				console.error( error );
 19332  
 19333  			}
 19334  
 19335  		}
 19336  
 19337  		function texImage2D() {
 19338  
 19339  			try {
 19340  
 19341  				gl.texImage2D.apply( gl, arguments );
 19342  
 19343  			} catch ( error ) {
 19344  
 19345  				console.error( error );
 19346  
 19347  			}
 19348  
 19349  		}
 19350  
 19351  		//
 19352  
 19353  		function scissor( scissor ) {
 19354  
 19355  			if ( currentScissor.equals( scissor ) === false ) {
 19356  
 19357  				gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
 19358  				currentScissor.copy( scissor );
 19359  
 19360  			}
 19361  
 19362  		}
 19363  
 19364  		function viewport( viewport ) {
 19365  
 19366  			if ( currentViewport.equals( viewport ) === false ) {
 19367  
 19368  				gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
 19369  				currentViewport.copy( viewport );
 19370  
 19371  			}
 19372  
 19373  		}
 19374  
 19375  		//
 19376  
 19377  		function reset() {
 19378  
 19379  			for ( var i = 0; i < enabledAttributes.length; i ++ ) {
 19380  
 19381  				if ( enabledAttributes[ i ] === 1 ) {
 19382  
 19383  					gl.disableVertexAttribArray( i );
 19384  					enabledAttributes[ i ] = 0;
 19385  
 19386  				}
 19387  
 19388  			}
 19389  
 19390  			capabilities = {};
 19391  
 19392  			compressedTextureFormats = null;
 19393  
 19394  			currentTextureSlot = null;
 19395  			currentBoundTextures = {};
 19396  
 19397  			currentBlending = null;
 19398  
 19399  			currentFlipSided = null;
 19400  			currentCullFace = null;
 19401  
 19402  			colorBuffer.reset();
 19403  			depthBuffer.reset();
 19404  			stencilBuffer.reset();
 19405  
 19406  		}
 19407  
 19408  		return {
 19409  
 19410  			buffers: {
 19411  				color: colorBuffer,
 19412  				depth: depthBuffer,
 19413  				stencil: stencilBuffer
 19414  			},
 19415  
 19416  			init: init,
 19417  			initAttributes: initAttributes,
 19418  			enableAttribute: enableAttribute,
 19419  			enableAttributeAndDivisor: enableAttributeAndDivisor,
 19420  			disableUnusedAttributes: disableUnusedAttributes,
 19421  			enable: enable,
 19422  			disable: disable,
 19423  			getCompressedTextureFormats: getCompressedTextureFormats,
 19424  
 19425  			setBlending: setBlending,
 19426  
 19427  			setColorWrite: setColorWrite,
 19428  			setDepthTest: setDepthTest,
 19429  			setDepthWrite: setDepthWrite,
 19430  			setDepthFunc: setDepthFunc,
 19431  			setStencilTest: setStencilTest,
 19432  			setStencilWrite: setStencilWrite,
 19433  			setStencilFunc: setStencilFunc,
 19434  			setStencilOp: setStencilOp,
 19435  
 19436  			setFlipSided: setFlipSided,
 19437  			setCullFace: setCullFace,
 19438  
 19439  			setLineWidth: setLineWidth,
 19440  			setPolygonOffset: setPolygonOffset,
 19441  
 19442  			getScissorTest: getScissorTest,
 19443  			setScissorTest: setScissorTest,
 19444  
 19445  			activeTexture: activeTexture,
 19446  			bindTexture: bindTexture,
 19447  			compressedTexImage2D: compressedTexImage2D,
 19448  			texImage2D: texImage2D,
 19449  
 19450  			scissor: scissor,
 19451  			viewport: viewport,
 19452  
 19453  			reset: reset
 19454  
 19455  		};
 19456  
 19457  	}
 19458  
 19459  	/**
 19460  	 * @author mrdoob / http://mrdoob.com/
 19461  	 */
 19462  
 19463  	function WebGLCapabilities( gl, extensions, parameters ) {
 19464  
 19465  		var maxAnisotropy;
 19466  
 19467  		function getMaxAnisotropy() {
 19468  
 19469  			if ( maxAnisotropy !== undefined ) return maxAnisotropy;
 19470  
 19471  			var extension = extensions.get( 'EXT_texture_filter_anisotropic' );
 19472  
 19473  			if ( extension !== null ) {
 19474  
 19475  				maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
 19476  
 19477  			} else {
 19478  
 19479  				maxAnisotropy = 0;
 19480  
 19481  			}
 19482  
 19483  			return maxAnisotropy;
 19484  
 19485  		}
 19486  
 19487  		function getMaxPrecision( precision ) {
 19488  
 19489  			if ( precision === 'highp' ) {
 19490  
 19491  				if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&
 19492  				     gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {
 19493  
 19494  					return 'highp';
 19495  
 19496  				}
 19497  
 19498  				precision = 'mediump';
 19499  
 19500  			}
 19501  
 19502  			if ( precision === 'mediump' ) {
 19503  
 19504  				if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&
 19505  				     gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {
 19506  
 19507  					return 'mediump';
 19508  
 19509  				}
 19510  
 19511  			}
 19512  
 19513  			return 'lowp';
 19514  
 19515  		}
 19516  
 19517  		var precision = parameters.precision !== undefined ? parameters.precision : 'highp';
 19518  		var maxPrecision = getMaxPrecision( precision );
 19519  
 19520  		if ( maxPrecision !== precision ) {
 19521  
 19522  			console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
 19523  			precision = maxPrecision;
 19524  
 19525  		}
 19526  
 19527  		var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true && !! extensions.get( 'EXT_frag_depth' );
 19528  
 19529  		var maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );
 19530  		var maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
 19531  		var maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE );
 19532  		var maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE );
 19533  
 19534  		var maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
 19535  		var maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS );
 19536  		var maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS );
 19537  		var maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS );
 19538  
 19539  		var vertexTextures = maxVertexTextures > 0;
 19540  		var floatFragmentTextures = !! extensions.get( 'OES_texture_float' );
 19541  		var floatVertexTextures = vertexTextures && floatFragmentTextures;
 19542  
 19543  		return {
 19544  
 19545  			getMaxAnisotropy: getMaxAnisotropy,
 19546  			getMaxPrecision: getMaxPrecision,
 19547  
 19548  			precision: precision,
 19549  			logarithmicDepthBuffer: logarithmicDepthBuffer,
 19550  
 19551  			maxTextures: maxTextures,
 19552  			maxVertexTextures: maxVertexTextures,
 19553  			maxTextureSize: maxTextureSize,
 19554  			maxCubemapSize: maxCubemapSize,
 19555  
 19556  			maxAttributes: maxAttributes,
 19557  			maxVertexUniforms: maxVertexUniforms,
 19558  			maxVaryings: maxVaryings,
 19559  			maxFragmentUniforms: maxFragmentUniforms,
 19560  
 19561  			vertexTextures: vertexTextures,
 19562  			floatFragmentTextures: floatFragmentTextures,
 19563  			floatVertexTextures: floatVertexTextures
 19564  
 19565  		};
 19566  
 19567  	}
 19568  
 19569  	/**
 19570  	 * @author mrdoob / http://mrdoob.com/
 19571  	 */
 19572  
 19573  	function WebGLExtensions( gl ) {
 19574  
 19575  		var extensions = {};
 19576  
 19577  		return {
 19578  
 19579  			get: function ( name ) {
 19580  
 19581  				if ( extensions[ name ] !== undefined ) {
 19582  
 19583  					return extensions[ name ];
 19584  
 19585  				}
 19586  
 19587  				var extension;
 19588  
 19589  				switch ( name ) {
 19590  
 19591  					case 'WEBGL_depth_texture':
 19592  						extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
 19593  						break;
 19594  
 19595  					case 'EXT_texture_filter_anisotropic':
 19596  						extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
 19597  						break;
 19598  
 19599  					case 'WEBGL_compressed_texture_s3tc':
 19600  						extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
 19601  						break;
 19602  
 19603  					case 'WEBGL_compressed_texture_pvrtc':
 19604  						extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
 19605  						break;
 19606  
 19607  					case 'WEBGL_compressed_texture_etc1':
 19608  						extension = gl.getExtension( 'WEBGL_compressed_texture_etc1' );
 19609  						break;
 19610  
 19611  					default:
 19612  						extension = gl.getExtension( name );
 19613  
 19614  				}
 19615  
 19616  				if ( extension === null ) {
 19617  
 19618  					console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
 19619  
 19620  				}
 19621  
 19622  				extensions[ name ] = extension;
 19623  
 19624  				return extension;
 19625  
 19626  			}
 19627  
 19628  		};
 19629  
 19630  	}
 19631  
 19632  	/**
 19633  	 * @author tschw
 19634  	 */
 19635  
 19636  	function WebGLClipping() {
 19637  
 19638  		var scope = this,
 19639  
 19640  			globalState = null,
 19641  			numGlobalPlanes = 0,
 19642  			localClippingEnabled = false,
 19643  			renderingShadows = false,
 19644  
 19645  			plane = new Plane(),
 19646  			viewNormalMatrix = new Matrix3(),
 19647  
 19648  			uniform = { value: null, needsUpdate: false };
 19649  
 19650  		this.uniform = uniform;
 19651  		this.numPlanes = 0;
 19652  		this.numIntersection = 0;
 19653  
 19654  		this.init = function( planes, enableLocalClipping, camera ) {
 19655  
 19656  			var enabled =
 19657  				planes.length !== 0 ||
 19658  				enableLocalClipping ||
 19659  				// enable state of previous frame - the clipping code has to
 19660  				// run another frame in order to reset the state:
 19661  				numGlobalPlanes !== 0 ||
 19662  				localClippingEnabled;
 19663  
 19664  			localClippingEnabled = enableLocalClipping;
 19665  
 19666  			globalState = projectPlanes( planes, camera, 0 );
 19667  			numGlobalPlanes = planes.length;
 19668  
 19669  			return enabled;
 19670  
 19671  		};
 19672  
 19673  		this.beginShadows = function() {
 19674  
 19675  			renderingShadows = true;
 19676  			projectPlanes( null );
 19677  
 19678  		};
 19679  
 19680  		this.endShadows = function() {
 19681  
 19682  			renderingShadows = false;
 19683  			resetGlobalState();
 19684  
 19685  		};
 19686  
 19687  		this.setState = function( planes, clipIntersection, clipShadows, camera, cache, fromCache ) {
 19688  
 19689  			if ( ! localClippingEnabled ||
 19690  					planes === null || planes.length === 0 ||
 19691  					renderingShadows && ! clipShadows ) {
 19692  				// there's no local clipping
 19693  
 19694  				if ( renderingShadows ) {
 19695  					// there's no global clipping
 19696  
 19697  					projectPlanes( null );
 19698  
 19699  				} else {
 19700  
 19701  					resetGlobalState();
 19702  				}
 19703  
 19704  			} else {
 19705  
 19706  				var nGlobal = renderingShadows ? 0 : numGlobalPlanes,
 19707  					lGlobal = nGlobal * 4,
 19708  
 19709  					dstArray = cache.clippingState || null;
 19710  
 19711  				uniform.value = dstArray; // ensure unique state
 19712  
 19713  				dstArray = projectPlanes( planes, camera, lGlobal, fromCache );
 19714  
 19715  				for ( var i = 0; i !== lGlobal; ++ i ) {
 19716  
 19717  					dstArray[ i ] = globalState[ i ];
 19718  
 19719  				}
 19720  
 19721  				cache.clippingState = dstArray;
 19722  				this.numIntersection = clipIntersection ? this.numPlanes : 0;
 19723  				this.numPlanes += nGlobal;
 19724  
 19725  			}
 19726  
 19727  
 19728  		};
 19729  
 19730  		function resetGlobalState() {
 19731  
 19732  			if ( uniform.value !== globalState ) {
 19733  
 19734  				uniform.value = globalState;
 19735  				uniform.needsUpdate = numGlobalPlanes > 0;
 19736  
 19737  			}
 19738  
 19739  			scope.numPlanes = numGlobalPlanes;
 19740  			scope.numIntersection = 0;
 19741  
 19742  		}
 19743  
 19744  		function projectPlanes( planes, camera, dstOffset, skipTransform ) {
 19745  
 19746  			var nPlanes = planes !== null ? planes.length : 0,
 19747  				dstArray = null;
 19748  
 19749  			if ( nPlanes !== 0 ) {
 19750  
 19751  				dstArray = uniform.value;
 19752  
 19753  				if ( skipTransform !== true || dstArray === null ) {
 19754  
 19755  					var flatSize = dstOffset + nPlanes * 4,
 19756  						viewMatrix = camera.matrixWorldInverse;
 19757  
 19758  					viewNormalMatrix.getNormalMatrix( viewMatrix );
 19759  
 19760  					if ( dstArray === null || dstArray.length < flatSize ) {
 19761  
 19762  						dstArray = new Float32Array( flatSize );
 19763  
 19764  					}
 19765  
 19766  					for ( var i = 0, i4 = dstOffset;
 19767  										i !== nPlanes; ++ i, i4 += 4 ) {
 19768  
 19769  						plane.copy( planes[ i ] ).
 19770  								applyMatrix4( viewMatrix, viewNormalMatrix );
 19771  
 19772  						plane.normal.toArray( dstArray, i4 );
 19773  						dstArray[ i4 + 3 ] = plane.constant;
 19774  
 19775  					}
 19776  
 19777  				}
 19778  
 19779  				uniform.value = dstArray;
 19780  				uniform.needsUpdate = true;
 19781  
 19782  			}
 19783  
 19784  			scope.numPlanes = nPlanes;
 19785  			
 19786  			return dstArray;
 19787  
 19788  		}
 19789  
 19790  	}
 19791  
 19792  	/**
 19793  	 * @author supereggbert / http://www.paulbrunt.co.uk/
 19794  	 * @author mrdoob / http://mrdoob.com/
 19795  	 * @author alteredq / http://alteredqualia.com/
 19796  	 * @author szimek / https://github.com/szimek/
 19797  	 * @author tschw
 19798  	 */
 19799  
 19800  	function WebGLRenderer( parameters ) {
 19801  
 19802  		console.log( 'THREE.WebGLRenderer', REVISION );
 19803  
 19804  		parameters = parameters || {};
 19805  
 19806  		var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ),
 19807  			_context = parameters.context !== undefined ? parameters.context : null,
 19808  
 19809  			_alpha = parameters.alpha !== undefined ? parameters.alpha : false,
 19810  			_depth = parameters.depth !== undefined ? parameters.depth : true,
 19811  			_stencil = parameters.stencil !== undefined ? parameters.stencil : true,
 19812  			_antialias = parameters.antialias !== undefined ? parameters.antialias : false,
 19813  			_premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
 19814  			_preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false;
 19815  
 19816  		var lights = [];
 19817  
 19818  		var opaqueObjects = [];
 19819  		var opaqueObjectsLastIndex = - 1;
 19820  		var transparentObjects = [];
 19821  		var transparentObjectsLastIndex = - 1;
 19822  
 19823  		var morphInfluences = new Float32Array( 8 );
 19824  
 19825  		var sprites = [];
 19826  		var lensFlares = [];
 19827  
 19828  		// public properties
 19829  
 19830  		this.domElement = _canvas;
 19831  		this.context = null;
 19832  
 19833  		// clearing
 19834  
 19835  		this.autoClear = true;
 19836  		this.autoClearColor = true;
 19837  		this.autoClearDepth = true;
 19838  		this.autoClearStencil = true;
 19839  
 19840  		// scene graph
 19841  
 19842  		this.sortObjects = true;
 19843  
 19844  		// user-defined clipping
 19845  
 19846  		this.clippingPlanes = [];
 19847  		this.localClippingEnabled = false;
 19848  
 19849  		// physically based shading
 19850  
 19851  		this.gammaFactor = 2.0;	// for backwards compatibility
 19852  		this.gammaInput = false;
 19853  		this.gammaOutput = false;
 19854  
 19855  		// physical lights
 19856  
 19857  		this.physicallyCorrectLights = false;
 19858  
 19859  		// tone mapping
 19860  
 19861  		this.toneMapping = LinearToneMapping;
 19862  		this.toneMappingExposure = 1.0;
 19863  		this.toneMappingWhitePoint = 1.0;
 19864  
 19865  		// morphs
 19866  
 19867  		this.maxMorphTargets = 8;
 19868  		this.maxMorphNormals = 4;
 19869  
 19870  		// internal properties
 19871  
 19872  		var _this = this,
 19873  
 19874  			// internal state cache
 19875  
 19876  			_currentProgram = null,
 19877  			_currentRenderTarget = null,
 19878  			_currentFramebuffer = null,
 19879  			_currentMaterialId = - 1,
 19880  			_currentGeometryProgram = '',
 19881  			_currentCamera = null,
 19882  
 19883  			_currentScissor = new Vector4(),
 19884  			_currentScissorTest = null,
 19885  
 19886  			_currentViewport = new Vector4(),
 19887  
 19888  			//
 19889  
 19890  			_usedTextureUnits = 0,
 19891  
 19892  			//
 19893  
 19894  			_clearColor = new Color( 0x000000 ),
 19895  			_clearAlpha = 0,
 19896  
 19897  			_width = _canvas.width,
 19898  			_height = _canvas.height,
 19899  
 19900  			_pixelRatio = 1,
 19901  
 19902  			_scissor = new Vector4( 0, 0, _width, _height ),
 19903  			_scissorTest = false,
 19904  
 19905  			_viewport = new Vector4( 0, 0, _width, _height ),
 19906  
 19907  			// frustum
 19908  
 19909  			_frustum = new Frustum(),
 19910  
 19911  			// clipping
 19912  
 19913  			_clipping = new WebGLClipping(),
 19914  			_clippingEnabled = false,
 19915  			_localClippingEnabled = false,
 19916  
 19917  			_sphere = new Sphere(),
 19918  
 19919  			// camera matrices cache
 19920  
 19921  			_projScreenMatrix = new Matrix4(),
 19922  
 19923  			_vector3 = new Vector3(),
 19924  			_matrix4 = new Matrix4(),
 19925  			_matrix42 = new Matrix4(),
 19926  
 19927  			// light arrays cache
 19928  
 19929  			_lights = {
 19930  
 19931  				hash: '',
 19932  
 19933  			ambient: [ 0, 0, 0 ],
 19934  			directional: [],
 19935  			directionalShadowMap: [],
 19936  			directionalShadowMatrix: [],
 19937  			spot: [],
 19938  			spotShadowMap: [],
 19939  			spotShadowMatrix: [],
 19940  			rectArea: [],
 19941  			point: [],
 19942  			pointShadowMap: [],
 19943  			pointShadowMatrix: [],
 19944  			hemi: [],
 19945  
 19946  				shadows: []
 19947  
 19948  			},
 19949  
 19950  			// info
 19951  
 19952  			_infoRender = {
 19953  
 19954  				calls: 0,
 19955  				vertices: 0,
 19956  				faces: 0,
 19957  				points: 0
 19958  
 19959  			};
 19960  
 19961  		this.info = {
 19962  
 19963  			render: _infoRender,
 19964  			memory: {
 19965  
 19966  				geometries: 0,
 19967  				textures: 0
 19968  
 19969  			},
 19970  			programs: null
 19971  
 19972  		};
 19973  
 19974  
 19975  		// initialize
 19976  
 19977  		var _gl;
 19978  
 19979  		try {
 19980  
 19981  			var attributes = {
 19982  				alpha: _alpha,
 19983  				depth: _depth,
 19984  				stencil: _stencil,
 19985  				antialias: _antialias,
 19986  				premultipliedAlpha: _premultipliedAlpha,
 19987  				preserveDrawingBuffer: _preserveDrawingBuffer
 19988  			};
 19989  
 19990  			_gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );
 19991  
 19992  			if ( _gl === null ) {
 19993  
 19994  				if ( _canvas.getContext( 'webgl' ) !== null ) {
 19995  
 19996  					throw 'Error creating WebGL context with your selected attributes.';
 19997  
 19998  				} else {
 19999  
 20000  					throw 'Error creating WebGL context.';
 20001  
 20002  				}
 20003  
 20004  			}
 20005  
 20006  			// Some experimental-webgl implementations do not have getShaderPrecisionFormat
 20007  
 20008  			if ( _gl.getShaderPrecisionFormat === undefined ) {
 20009  
 20010  				_gl.getShaderPrecisionFormat = function () {
 20011  
 20012  					return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
 20013  
 20014  				};
 20015  
 20016  			}
 20017  
 20018  			_canvas.addEventListener( 'webglcontextlost', onContextLost, false );
 20019  
 20020  		} catch ( error ) {
 20021  
 20022  			console.error( 'THREE.WebGLRenderer: ' + error );
 20023  
 20024  		}
 20025  
 20026  		var extensions = new WebGLExtensions( _gl );
 20027  
 20028  		extensions.get( 'WEBGL_depth_texture' );
 20029  		extensions.get( 'OES_texture_float' );
 20030  		extensions.get( 'OES_texture_float_linear' );
 20031  		extensions.get( 'OES_texture_half_float' );
 20032  		extensions.get( 'OES_texture_half_float_linear' );
 20033  		extensions.get( 'OES_standard_derivatives' );
 20034  		extensions.get( 'ANGLE_instanced_arrays' );
 20035  
 20036  		if ( extensions.get( 'OES_element_index_uint' ) ) {
 20037  
 20038  			BufferGeometry.MaxIndex = 4294967296;
 20039  
 20040  		}
 20041  
 20042  		var capabilities = new WebGLCapabilities( _gl, extensions, parameters );
 20043  
 20044  		var state = new WebGLState( _gl, extensions, paramThreeToGL );
 20045  		var properties = new WebGLProperties();
 20046  		var textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, paramThreeToGL, this.info );
 20047  		var objects = new WebGLObjects( _gl, properties, this.info );
 20048  		var programCache = new WebGLPrograms( this, capabilities );
 20049  		var lightCache = new WebGLLights();
 20050  
 20051  		this.info.programs = programCache.programs;
 20052  
 20053  		var bufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender );
 20054  		var indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, _infoRender );
 20055  
 20056  		//
 20057  
 20058  		var backgroundPlaneCamera, backgroundPlaneMesh;
 20059  		var backgroundBoxCamera, backgroundBoxMesh;
 20060  
 20061  		//
 20062  
 20063  		function getTargetPixelRatio() {
 20064  
 20065  			return _currentRenderTarget === null ? _pixelRatio : 1;
 20066  
 20067  		}
 20068  
 20069  		function setDefaultGLState() {
 20070  
 20071  			state.init();
 20072  
 20073  			state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );
 20074  			state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );
 20075  
 20076  			state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha );
 20077  
 20078  		}
 20079  
 20080  		function resetGLState() {
 20081  
 20082  			_currentProgram = null;
 20083  			_currentCamera = null;
 20084  
 20085  			_currentGeometryProgram = '';
 20086  			_currentMaterialId = - 1;
 20087  
 20088  			state.reset();
 20089  
 20090  		}
 20091  
 20092  		setDefaultGLState();
 20093  
 20094  		this.context = _gl;
 20095  		this.capabilities = capabilities;
 20096  		this.extensions = extensions;
 20097  		this.properties = properties;
 20098  		this.state = state;
 20099  
 20100  		// shadow map
 20101  
 20102  		var shadowMap = new WebGLShadowMap( this, _lights, objects, capabilities );
 20103  
 20104  		this.shadowMap = shadowMap;
 20105  
 20106  
 20107  		// Plugins
 20108  
 20109  		var spritePlugin = new SpritePlugin( this, sprites );
 20110  		var lensFlarePlugin = new LensFlarePlugin( this, lensFlares );
 20111  
 20112  		// API
 20113  
 20114  		this.getContext = function () {
 20115  
 20116  			return _gl;
 20117  
 20118  		};
 20119  
 20120  		this.getContextAttributes = function () {
 20121  
 20122  			return _gl.getContextAttributes();
 20123  
 20124  		};
 20125  
 20126  		this.forceContextLoss = function () {
 20127  
 20128  			extensions.get( 'WEBGL_lose_context' ).loseContext();
 20129  
 20130  		};
 20131  
 20132  		this.getMaxAnisotropy = function () {
 20133  
 20134  			return capabilities.getMaxAnisotropy();
 20135  
 20136  		};
 20137  
 20138  		this.getPrecision = function () {
 20139  
 20140  			return capabilities.precision;
 20141  
 20142  		};
 20143  
 20144  		this.getPixelRatio = function () {
 20145  
 20146  			return _pixelRatio;
 20147  
 20148  		};
 20149  
 20150  		this.setPixelRatio = function ( value ) {
 20151  
 20152  			if ( value === undefined ) return;
 20153  
 20154  			_pixelRatio = value;
 20155  
 20156  			this.setSize( _viewport.z, _viewport.w, false );
 20157  
 20158  		};
 20159  
 20160  		this.getSize = function () {
 20161  
 20162  			return {
 20163  				width: _width,
 20164  				height: _height
 20165  			};
 20166  
 20167  		};
 20168  
 20169  		this.setSize = function ( width, height, updateStyle ) {
 20170  
 20171  			_width = width;
 20172  			_height = height;
 20173  
 20174  			_canvas.width = width * _pixelRatio;
 20175  			_canvas.height = height * _pixelRatio;
 20176  
 20177  			if ( updateStyle !== false ) {
 20178  
 20179  				_canvas.style.width = width + 'px';
 20180  				_canvas.style.height = height + 'px';
 20181  
 20182  			}
 20183  
 20184  			this.setViewport( 0, 0, width, height );
 20185  
 20186  		};
 20187  
 20188  		this.setViewport = function ( x, y, width, height ) {
 20189  
 20190  			state.viewport( _viewport.set( x, y, width, height ) );
 20191  
 20192  		};
 20193  
 20194  		this.setScissor = function ( x, y, width, height ) {
 20195  
 20196  			state.scissor( _scissor.set( x, y, width, height ) );
 20197  
 20198  		};
 20199  
 20200  		this.setScissorTest = function ( boolean ) {
 20201  
 20202  			state.setScissorTest( _scissorTest = boolean );
 20203  
 20204  		};
 20205  
 20206  		// Clearing
 20207  
 20208  		this.getClearColor = function () {
 20209  
 20210  			return _clearColor;
 20211  
 20212  		};
 20213  
 20214  		this.setClearColor = function ( color, alpha ) {
 20215  
 20216  			_clearColor.set( color );
 20217  
 20218  			_clearAlpha = alpha !== undefined ? alpha : 1;
 20219  
 20220  			state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha );
 20221  
 20222  		};
 20223  
 20224  		this.getClearAlpha = function () {
 20225  
 20226  			return _clearAlpha;
 20227  
 20228  		};
 20229  
 20230  		this.setClearAlpha = function ( alpha ) {
 20231  
 20232  			_clearAlpha = alpha;
 20233  
 20234  			state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha );
 20235  
 20236  		};
 20237  
 20238  		this.clear = function ( color, depth, stencil ) {
 20239  
 20240  			var bits = 0;
 20241  
 20242  			if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;
 20243  			if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;
 20244  			if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;
 20245  
 20246  			_gl.clear( bits );
 20247  
 20248  		};
 20249  
 20250  		this.clearColor = function () {
 20251  
 20252  			this.clear( true, false, false );
 20253  
 20254  		};
 20255  
 20256  		this.clearDepth = function () {
 20257  
 20258  			this.clear( false, true, false );
 20259  
 20260  		};
 20261  
 20262  		this.clearStencil = function () {
 20263  
 20264  			this.clear( false, false, true );
 20265  
 20266  		};
 20267  
 20268  		this.clearTarget = function ( renderTarget, color, depth, stencil ) {
 20269  
 20270  			this.setRenderTarget( renderTarget );
 20271  			this.clear( color, depth, stencil );
 20272  
 20273  		};
 20274  
 20275  		// Reset
 20276  
 20277  		this.resetGLState = resetGLState;
 20278  
 20279  		this.dispose = function() {
 20280  
 20281  			transparentObjects = [];
 20282  			transparentObjectsLastIndex = -1;
 20283  			opaqueObjects = [];
 20284  			opaqueObjectsLastIndex = -1;
 20285  
 20286  			_canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
 20287  
 20288  		};
 20289  
 20290  		// Events
 20291  
 20292  		function onContextLost( event ) {
 20293  
 20294  			event.preventDefault();
 20295  
 20296  			resetGLState();
 20297  			setDefaultGLState();
 20298  
 20299  			properties.clear();
 20300  
 20301  		}
 20302  
 20303  		function onMaterialDispose( event ) {
 20304  
 20305  			var material = event.target;
 20306  
 20307  			material.removeEventListener( 'dispose', onMaterialDispose );
 20308  
 20309  			deallocateMaterial( material );
 20310  
 20311  		}
 20312  
 20313  		// Buffer deallocation
 20314  
 20315  		function deallocateMaterial( material ) {
 20316  
 20317  			releaseMaterialProgramReference( material );
 20318  
 20319  			properties.delete( material );
 20320  
 20321  		}
 20322  
 20323  
 20324  		function releaseMaterialProgramReference( material ) {
 20325  
 20326  			var programInfo = properties.get( material ).program;
 20327  
 20328  			material.program = undefined;
 20329  
 20330  			if ( programInfo !== undefined ) {
 20331  
 20332  				programCache.releaseProgram( programInfo );
 20333  
 20334  			}
 20335  
 20336  		}
 20337  
 20338  		// Buffer rendering
 20339  
 20340  		this.renderBufferImmediate = function ( object, program, material ) {
 20341  
 20342  			state.initAttributes();
 20343  
 20344  			var buffers = properties.get( object );
 20345  
 20346  			if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer();
 20347  			if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer();
 20348  			if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer();
 20349  			if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer();
 20350  
 20351  			var attributes = program.getAttributes();
 20352  
 20353  			if ( object.hasPositions ) {
 20354  
 20355  				_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position );
 20356  				_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
 20357  
 20358  				state.enableAttribute( attributes.position );
 20359  				_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
 20360  
 20361  			}
 20362  
 20363  			if ( object.hasNormals ) {
 20364  
 20365  				_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal );
 20366  
 20367  				if ( ! material.isMeshPhongMaterial &&
 20368  					! material.isMeshStandardMaterial &&
 20369  					! material.isMeshNormalMaterial &&
 20370  					material.shading === FlatShading ) {
 20371  
 20372  					for ( var i = 0, l = object.count * 3; i < l; i += 9 ) {
 20373  
 20374  						var array = object.normalArray;
 20375  
 20376  						var nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3;
 20377  						var ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3;
 20378  						var nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3;
 20379  
 20380  						array[ i + 0 ] = nx;
 20381  						array[ i + 1 ] = ny;
 20382  						array[ i + 2 ] = nz;
 20383  
 20384  						array[ i + 3 ] = nx;
 20385  						array[ i + 4 ] = ny;
 20386  						array[ i + 5 ] = nz;
 20387  
 20388  						array[ i + 6 ] = nx;
 20389  						array[ i + 7 ] = ny;
 20390  						array[ i + 8 ] = nz;
 20391  
 20392  					}
 20393  
 20394  				}
 20395  
 20396  				_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
 20397  
 20398  				state.enableAttribute( attributes.normal );
 20399  
 20400  				_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
 20401  
 20402  			}
 20403  
 20404  			if ( object.hasUvs && material.map ) {
 20405  
 20406  				_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv );
 20407  				_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
 20408  
 20409  				state.enableAttribute( attributes.uv );
 20410  
 20411  				_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
 20412  
 20413  			}
 20414  
 20415  			if ( object.hasColors && material.vertexColors !== NoColors ) {
 20416  
 20417  				_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color );
 20418  				_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
 20419  
 20420  				state.enableAttribute( attributes.color );
 20421  
 20422  				_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );
 20423  
 20424  			}
 20425  
 20426  			state.disableUnusedAttributes();
 20427  
 20428  			_gl.drawArrays( _gl.TRIANGLES, 0, object.count );
 20429  
 20430  			object.count = 0;
 20431  
 20432  		};
 20433  
 20434  		this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) {
 20435  
 20436  			setMaterial( material );
 20437  
 20438  			var program = setProgram( camera, fog, material, object );
 20439  
 20440  			var updateBuffers = false;
 20441  			var geometryProgram = geometry.id + '_' + program.id + '_' + material.wireframe;
 20442  
 20443  			if ( geometryProgram !== _currentGeometryProgram ) {
 20444  
 20445  				_currentGeometryProgram = geometryProgram;
 20446  				updateBuffers = true;
 20447  
 20448  			}
 20449  
 20450  			// morph targets
 20451  
 20452  			var morphTargetInfluences = object.morphTargetInfluences;
 20453  
 20454  			if ( morphTargetInfluences !== undefined ) {
 20455  
 20456  				var activeInfluences = [];
 20457  
 20458  				for ( var i = 0, l = morphTargetInfluences.length; i < l; i ++ ) {
 20459  
 20460  					var influence = morphTargetInfluences[ i ];
 20461  					activeInfluences.push( [ influence, i ] );
 20462  
 20463  				}
 20464  
 20465  				activeInfluences.sort( absNumericalSort );
 20466  
 20467  				if ( activeInfluences.length > 8 ) {
 20468  
 20469  					activeInfluences.length = 8;
 20470  
 20471  				}
 20472  
 20473  				var morphAttributes = geometry.morphAttributes;
 20474  
 20475  				for ( var i = 0, l = activeInfluences.length; i < l; i ++ ) {
 20476  
 20477  					var influence = activeInfluences[ i ];
 20478  					morphInfluences[ i ] = influence[ 0 ];
 20479  
 20480  					if ( influence[ 0 ] !== 0 ) {
 20481  
 20482  						var index = influence[ 1 ];
 20483  
 20484  						if ( material.morphTargets === true && morphAttributes.position ) geometry.addAttribute( 'morphTarget' + i, morphAttributes.position[ index ] );
 20485  						if ( material.morphNormals === true && morphAttributes.normal ) geometry.addAttribute( 'morphNormal' + i, morphAttributes.normal[ index ] );
 20486  
 20487  					} else {
 20488  
 20489  						if ( material.morphTargets === true ) geometry.removeAttribute( 'morphTarget' + i );
 20490  						if ( material.morphNormals === true ) geometry.removeAttribute( 'morphNormal' + i );
 20491  
 20492  					}
 20493  
 20494  				}
 20495  
 20496  				for ( var i = activeInfluences.length, il = morphInfluences.length; i < il; i ++ ) {
 20497  
 20498  					morphInfluences[ i ] = 0.0;
 20499  
 20500  				}
 20501  
 20502  				program.getUniforms().setValue(
 20503  					_gl, 'morphTargetInfluences', morphInfluences );
 20504  
 20505  				updateBuffers = true;
 20506  
 20507  			}
 20508  
 20509  			//
 20510  
 20511  			var index = geometry.index;
 20512  			var position = geometry.attributes.position;
 20513  			var rangeFactor = 1;
 20514  
 20515  			if ( material.wireframe === true ) {
 20516  
 20517  				index = objects.getWireframeAttribute( geometry );
 20518  				rangeFactor = 2;
 20519  
 20520  			}
 20521  
 20522  			var renderer;
 20523  
 20524  			if ( index !== null ) {
 20525  
 20526  				renderer = indexedBufferRenderer;
 20527  				renderer.setIndex( index );
 20528  
 20529  			} else {
 20530  
 20531  				renderer = bufferRenderer;
 20532  
 20533  			}
 20534  
 20535  			if ( updateBuffers ) {
 20536  
 20537  				setupVertexAttributes( material, program, geometry );
 20538  
 20539  				if ( index !== null ) {
 20540  
 20541  					_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, objects.getAttributeBuffer( index ) );
 20542  
 20543  				}
 20544  
 20545  			}
 20546  
 20547  			//
 20548  
 20549  			var dataCount = 0;
 20550  
 20551  			if ( index !== null ) {
 20552  
 20553  				dataCount = index.count;
 20554  
 20555  			} else if ( position !== undefined ) {
 20556  
 20557  				dataCount = position.count;
 20558  
 20559  			}
 20560  
 20561  			var rangeStart = geometry.drawRange.start * rangeFactor;
 20562  			var rangeCount = geometry.drawRange.count * rangeFactor;
 20563  
 20564  			var groupStart = group !== null ? group.start * rangeFactor : 0;
 20565  			var groupCount = group !== null ? group.count * rangeFactor : Infinity;
 20566  
 20567  			var drawStart = Math.max( rangeStart, groupStart );
 20568  			var drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1;
 20569  
 20570  			var drawCount = Math.max( 0, drawEnd - drawStart + 1 );
 20571  
 20572  			if ( drawCount === 0 ) return;
 20573  
 20574  			//
 20575  
 20576  			if ( object.isMesh ) {
 20577  
 20578  				if ( material.wireframe === true ) {
 20579  
 20580  					state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
 20581  					renderer.setMode( _gl.LINES );
 20582  
 20583  				} else {
 20584  
 20585  					switch ( object.drawMode ) {
 20586  
 20587  						case TrianglesDrawMode:
 20588  							renderer.setMode( _gl.TRIANGLES );
 20589  							break;
 20590  
 20591  						case TriangleStripDrawMode:
 20592  							renderer.setMode( _gl.TRIANGLE_STRIP );
 20593  							break;
 20594  
 20595  						case TriangleFanDrawMode:
 20596  							renderer.setMode( _gl.TRIANGLE_FAN );
 20597  							break;
 20598  
 20599  					}
 20600  
 20601  				}
 20602  
 20603  
 20604  			} else if ( object.isLine ) {
 20605  
 20606  				var lineWidth = material.linewidth;
 20607  
 20608  				if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
 20609  
 20610  				state.setLineWidth( lineWidth * getTargetPixelRatio() );
 20611  
 20612  				if ( object.isLineSegments ) {
 20613  
 20614  					renderer.setMode( _gl.LINES );
 20615  
 20616  				} else {
 20617  
 20618  					renderer.setMode( _gl.LINE_STRIP );
 20619  
 20620  				}
 20621  
 20622  			} else if ( object.isPoints ) {
 20623  
 20624  				renderer.setMode( _gl.POINTS );
 20625  
 20626  			}
 20627  
 20628  			if ( geometry && geometry.isInstancedBufferGeometry ) {
 20629  
 20630  				if ( geometry.maxInstancedCount > 0 ) {
 20631  
 20632  					renderer.renderInstances( geometry, drawStart, drawCount );
 20633  
 20634  				}
 20635  
 20636  			} else {
 20637  
 20638  				renderer.render( drawStart, drawCount );
 20639  
 20640  			}
 20641  
 20642  		};
 20643  
 20644  		function setupVertexAttributes( material, program, geometry, startIndex ) {
 20645  
 20646  			var extension;
 20647  
 20648  			if ( geometry && geometry.isInstancedBufferGeometry ) {
 20649  
 20650  				extension = extensions.get( 'ANGLE_instanced_arrays' );
 20651  
 20652  				if ( extension === null ) {
 20653  
 20654  					console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
 20655  					return;
 20656  
 20657  				}
 20658  
 20659  			}
 20660  
 20661  			if ( startIndex === undefined ) startIndex = 0;
 20662  
 20663  			state.initAttributes();
 20664  
 20665  			var geometryAttributes = geometry.attributes;
 20666  
 20667  			var programAttributes = program.getAttributes();
 20668  
 20669  			var materialDefaultAttributeValues = material.defaultAttributeValues;
 20670  
 20671  			for ( var name in programAttributes ) {
 20672  
 20673  				var programAttribute = programAttributes[ name ];
 20674  
 20675  				if ( programAttribute >= 0 ) {
 20676  
 20677  					var geometryAttribute = geometryAttributes[ name ];
 20678  
 20679  					if ( geometryAttribute !== undefined ) {
 20680  
 20681  						var normalized = geometryAttribute.normalized;
 20682  						var size = geometryAttribute.itemSize;
 20683  
 20684  						var attributeProperties = objects.getAttributeProperties( geometryAttribute );
 20685  
 20686  						var buffer = attributeProperties.__webglBuffer;
 20687  						var type = attributeProperties.type;
 20688  						var bytesPerElement = attributeProperties.bytesPerElement;
 20689  
 20690  						if ( geometryAttribute.isInterleavedBufferAttribute ) {
 20691  
 20692  							var data = geometryAttribute.data;
 20693  							var stride = data.stride;
 20694  							var offset = geometryAttribute.offset;
 20695  
 20696  							if ( data && data.isInstancedInterleavedBuffer ) {
 20697  
 20698  								state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute, extension );
 20699  
 20700  								if ( geometry.maxInstancedCount === undefined ) {
 20701  
 20702  									geometry.maxInstancedCount = data.meshPerAttribute * data.count;
 20703  
 20704  								}
 20705  
 20706  							} else {
 20707  
 20708  								state.enableAttribute( programAttribute );
 20709  
 20710  							}
 20711  
 20712  							_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
 20713  							_gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, ( startIndex * stride + offset ) * bytesPerElement );
 20714  
 20715  						} else {
 20716  
 20717  							if ( geometryAttribute.isInstancedBufferAttribute ) {
 20718  
 20719  								state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute, extension );
 20720  
 20721  								if ( geometry.maxInstancedCount === undefined ) {
 20722  
 20723  									geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
 20724  
 20725  								}
 20726  
 20727  							} else {
 20728  
 20729  								state.enableAttribute( programAttribute );
 20730  
 20731  							}
 20732  
 20733  							_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
 20734  							_gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, startIndex * size * bytesPerElement );
 20735  
 20736  						}
 20737  
 20738  					} else if ( materialDefaultAttributeValues !== undefined ) {
 20739  
 20740  						var value = materialDefaultAttributeValues[ name ];
 20741  
 20742  						if ( value !== undefined ) {
 20743  
 20744  							switch ( value.length ) {
 20745  
 20746  								case 2:
 20747  									_gl.vertexAttrib2fv( programAttribute, value );
 20748  									break;
 20749  
 20750  								case 3:
 20751  									_gl.vertexAttrib3fv( programAttribute, value );
 20752  									break;
 20753  
 20754  								case 4:
 20755  									_gl.vertexAttrib4fv( programAttribute, value );
 20756  									break;
 20757  
 20758  								default:
 20759  									_gl.vertexAttrib1fv( programAttribute, value );
 20760  
 20761  							}
 20762  
 20763  						}
 20764  
 20765  					}
 20766  
 20767  				}
 20768  
 20769  			}
 20770  
 20771  			state.disableUnusedAttributes();
 20772  
 20773  		}
 20774  
 20775  		// Sorting
 20776  
 20777  		function absNumericalSort( a, b ) {
 20778  
 20779  			return Math.abs( b[ 0 ] ) - Math.abs( a[ 0 ] );
 20780  
 20781  		}
 20782  
 20783  		function painterSortStable( a, b ) {
 20784  
 20785  			if ( a.object.renderOrder !== b.object.renderOrder ) {
 20786  
 20787  				return a.object.renderOrder - b.object.renderOrder;
 20788  
 20789  			} else if ( a.material.program && b.material.program && a.material.program !== b.material.program ) {
 20790  
 20791  				return a.material.program.id - b.material.program.id;
 20792  
 20793  			} else if ( a.material.id !== b.material.id ) {
 20794  
 20795  				return a.material.id - b.material.id;
 20796  
 20797  			} else if ( a.z !== b.z ) {
 20798  
 20799  				return a.z - b.z;
 20800  
 20801  			} else {
 20802  
 20803  				return a.id - b.id;
 20804  
 20805  			}
 20806  
 20807  		}
 20808  
 20809  		function reversePainterSortStable( a, b ) {
 20810  
 20811  			if ( a.object.renderOrder !== b.object.renderOrder ) {
 20812  
 20813  				return a.object.renderOrder - b.object.renderOrder;
 20814  
 20815  			} if ( a.z !== b.z ) {
 20816  
 20817  				return b.z - a.z;
 20818  
 20819  			} else {
 20820  
 20821  				return a.id - b.id;
 20822  
 20823  			}
 20824  
 20825  		}
 20826  
 20827  		// Rendering
 20828  
 20829  		this.render = function ( scene, camera, renderTarget, forceClear ) {
 20830  
 20831  			if ( camera !== undefined && camera.isCamera !== true ) {
 20832  
 20833  				console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
 20834  				return;
 20835  
 20836  			}
 20837  
 20838  			// reset caching for this frame
 20839  
 20840  			_currentGeometryProgram = '';
 20841  			_currentMaterialId = - 1;
 20842  			_currentCamera = null;
 20843  
 20844  			// update scene graph
 20845  
 20846  			if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
 20847  
 20848  			// update camera matrices and frustum
 20849  
 20850  			if ( camera.parent === null ) camera.updateMatrixWorld();
 20851  
 20852  			camera.matrixWorldInverse.getInverse( camera.matrixWorld );
 20853  
 20854  			_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
 20855  			_frustum.setFromMatrix( _projScreenMatrix );
 20856  
 20857  			lights.length = 0;
 20858  
 20859  			opaqueObjectsLastIndex = - 1;
 20860  			transparentObjectsLastIndex = - 1;
 20861  
 20862  			sprites.length = 0;
 20863  			lensFlares.length = 0;
 20864  
 20865  			_localClippingEnabled = this.localClippingEnabled;
 20866  			_clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera );
 20867  
 20868  			projectObject( scene, camera );
 20869  
 20870  			opaqueObjects.length = opaqueObjectsLastIndex + 1;
 20871  			transparentObjects.length = transparentObjectsLastIndex + 1;
 20872  
 20873  			if ( _this.sortObjects === true ) {
 20874  
 20875  				opaqueObjects.sort( painterSortStable );
 20876  				transparentObjects.sort( reversePainterSortStable );
 20877  
 20878  			}
 20879  
 20880  			//
 20881  
 20882  			if ( _clippingEnabled ) _clipping.beginShadows();
 20883  
 20884  			setupShadows( lights );
 20885  
 20886  			shadowMap.render( scene, camera );
 20887  
 20888  			setupLights( lights, camera );
 20889  
 20890  			if ( _clippingEnabled ) _clipping.endShadows();
 20891  
 20892  			//
 20893  
 20894  			_infoRender.calls = 0;
 20895  			_infoRender.vertices = 0;
 20896  			_infoRender.faces = 0;
 20897  			_infoRender.points = 0;
 20898  
 20899  			if ( renderTarget === undefined ) {
 20900  
 20901  				renderTarget = null;
 20902  
 20903  			}
 20904  
 20905  			this.setRenderTarget( renderTarget );
 20906  
 20907  			//
 20908  
 20909  			var background = scene.background;
 20910  
 20911  			if ( background === null ) {
 20912  
 20913  				state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha );
 20914  
 20915  			} else if ( background && background.isColor ) {
 20916  
 20917  				state.buffers.color.setClear( background.r, background.g, background.b, 1, _premultipliedAlpha );
 20918  				forceClear = true;
 20919  
 20920  			}
 20921  
 20922  			if ( this.autoClear || forceClear ) {
 20923  
 20924  				this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil );
 20925  
 20926  			}
 20927  
 20928  			if ( background && background.isCubeTexture ) {
 20929  
 20930  				if ( backgroundBoxCamera === undefined ) {
 20931  
 20932  					backgroundBoxCamera = new PerspectiveCamera();
 20933  
 20934  					backgroundBoxMesh = new Mesh(
 20935  						new BoxBufferGeometry( 5, 5, 5 ),
 20936  						new ShaderMaterial( {
 20937  							uniforms: ShaderLib.cube.uniforms,
 20938  							vertexShader: ShaderLib.cube.vertexShader,
 20939  							fragmentShader: ShaderLib.cube.fragmentShader,
 20940  							side: BackSide,
 20941  							depthTest: false,
 20942  							depthWrite: false,
 20943  							fog: false
 20944  						} )
 20945  					);
 20946  
 20947  				}
 20948  
 20949  				backgroundBoxCamera.projectionMatrix.copy( camera.projectionMatrix );
 20950  
 20951  				backgroundBoxCamera.matrixWorld.extractRotation( camera.matrixWorld );
 20952  				backgroundBoxCamera.matrixWorldInverse.getInverse( backgroundBoxCamera.matrixWorld );
 20953  
 20954  
 20955  				backgroundBoxMesh.material.uniforms[ "tCube" ].value = background;
 20956  				backgroundBoxMesh.modelViewMatrix.multiplyMatrices( backgroundBoxCamera.matrixWorldInverse, backgroundBoxMesh.matrixWorld );
 20957  
 20958  				objects.update( backgroundBoxMesh );
 20959  
 20960  				_this.renderBufferDirect( backgroundBoxCamera, null, backgroundBoxMesh.geometry, backgroundBoxMesh.material, backgroundBoxMesh, null );
 20961  
 20962  			} else if ( background && background.isTexture ) {
 20963  
 20964  				if ( backgroundPlaneCamera === undefined ) {
 20965  
 20966  					backgroundPlaneCamera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
 20967  
 20968  					backgroundPlaneMesh = new Mesh(
 20969  						new PlaneBufferGeometry( 2, 2 ),
 20970  						new MeshBasicMaterial( { depthTest: false, depthWrite: false, fog: false } )
 20971  					);
 20972  
 20973  				}
 20974  
 20975  				backgroundPlaneMesh.material.map = background;
 20976  
 20977  				objects.update( backgroundPlaneMesh );
 20978  
 20979  				_this.renderBufferDirect( backgroundPlaneCamera, null, backgroundPlaneMesh.geometry, backgroundPlaneMesh.material, backgroundPlaneMesh, null );
 20980  
 20981  			}
 20982  
 20983  			//
 20984  
 20985  			if ( scene.overrideMaterial ) {
 20986  
 20987  				var overrideMaterial = scene.overrideMaterial;
 20988  
 20989  				renderObjects( opaqueObjects, scene, camera, overrideMaterial );
 20990  				renderObjects( transparentObjects, scene, camera, overrideMaterial );
 20991  
 20992  			} else {
 20993  
 20994  				// opaque pass (front-to-back order)
 20995  
 20996  				state.setBlending( NoBlending );
 20997  				renderObjects( opaqueObjects, scene, camera );
 20998  
 20999  				// transparent pass (back-to-front order)
 21000  
 21001  				renderObjects( transparentObjects, scene, camera );
 21002  
 21003  			}
 21004  
 21005  			// custom render plugins (post pass)
 21006  
 21007  			spritePlugin.render( scene, camera );
 21008  			lensFlarePlugin.render( scene, camera, _currentViewport );
 21009  
 21010  			// Generate mipmap if we're using any kind of mipmap filtering
 21011  
 21012  			if ( renderTarget ) {
 21013  
 21014  				textures.updateRenderTargetMipmap( renderTarget );
 21015  
 21016  			}
 21017  
 21018  			// Ensure depth buffer writing is enabled so it can be cleared on next render
 21019  
 21020  			state.setDepthTest( true );
 21021  			state.setDepthWrite( true );
 21022  			state.setColorWrite( true );
 21023  
 21024  			// _gl.finish();
 21025  
 21026  		};
 21027  
 21028  		function pushRenderItem( object, geometry, material, z, group ) {
 21029  
 21030  			var array, index;
 21031  
 21032  			// allocate the next position in the appropriate array
 21033  
 21034  			if ( material.transparent ) {
 21035  
 21036  				array = transparentObjects;
 21037  				index = ++ transparentObjectsLastIndex;
 21038  
 21039  			} else {
 21040  
 21041  				array = opaqueObjects;
 21042  				index = ++ opaqueObjectsLastIndex;
 21043  
 21044  			}
 21045  
 21046  			// recycle existing render item or grow the array
 21047  
 21048  			var renderItem = array[ index ];
 21049  
 21050  			if ( renderItem !== undefined ) {
 21051  
 21052  				renderItem.id = object.id;
 21053  				renderItem.object = object;
 21054  				renderItem.geometry = geometry;
 21055  				renderItem.material = material;
 21056  				renderItem.z = _vector3.z;
 21057  				renderItem.group = group;
 21058  
 21059  			} else {
 21060  
 21061  				renderItem = {
 21062  					id: object.id,
 21063  					object: object,
 21064  					geometry: geometry,
 21065  					material: material,
 21066  					z: _vector3.z,
 21067  					group: group
 21068  				};
 21069  
 21070  				// assert( index === array.length );
 21071  				array.push( renderItem );
 21072  
 21073  			}
 21074  
 21075  		}
 21076  
 21077  		// TODO Duplicated code (Frustum)
 21078  
 21079  		function isObjectViewable( object ) {
 21080  
 21081  			var geometry = object.geometry;
 21082  
 21083  			if ( geometry.boundingSphere === null )
 21084  				geometry.computeBoundingSphere();
 21085  
 21086  			_sphere.copy( geometry.boundingSphere ).
 21087  			applyMatrix4( object.matrixWorld );
 21088  
 21089  			return isSphereViewable( _sphere );
 21090  
 21091  		}
 21092  
 21093  		function isSpriteViewable( sprite ) {
 21094  
 21095  			_sphere.center.set( 0, 0, 0 );
 21096  			_sphere.radius = 0.7071067811865476;
 21097  			_sphere.applyMatrix4( sprite.matrixWorld );
 21098  
 21099  			return isSphereViewable( _sphere );
 21100  
 21101  		}
 21102  
 21103  		function isSphereViewable( sphere ) {
 21104  
 21105  			if ( ! _frustum.intersectsSphere( sphere ) ) return false;
 21106  
 21107  			var numPlanes = _clipping.numPlanes;
 21108  
 21109  			if ( numPlanes === 0 ) return true;
 21110  
 21111  			var planes = _this.clippingPlanes,
 21112  
 21113  				center = sphere.center,
 21114  				negRad = - sphere.radius,
 21115  				i = 0;
 21116  
 21117  			do {
 21118  
 21119  				// out when deeper than radius in the negative halfspace
 21120  				if ( planes[ i ].distanceToPoint( center ) < negRad ) return false;
 21121  
 21122  			} while ( ++ i !== numPlanes );
 21123  
 21124  			return true;
 21125  
 21126  		}
 21127  
 21128  		function projectObject( object, camera ) {
 21129  
 21130  			if ( object.visible === false ) return;
 21131  
 21132  			var visible = ( object.layers.mask & camera.layers.mask ) !== 0;
 21133  
 21134  			if ( visible ) {
 21135  
 21136  				if ( object.isLight ) {
 21137  
 21138  					lights.push( object );
 21139  
 21140  				} else if ( object.isSprite ) {
 21141  
 21142  					if ( object.frustumCulled === false || isSpriteViewable( object ) === true ) {
 21143  
 21144  						sprites.push( object );
 21145  
 21146  					}
 21147  
 21148  				} else if ( object.isLensFlare ) {
 21149  
 21150  					lensFlares.push( object );
 21151  
 21152  				} else if ( object.isImmediateRenderObject ) {
 21153  
 21154  					if ( _this.sortObjects === true ) {
 21155  
 21156  						_vector3.setFromMatrixPosition( object.matrixWorld );
 21157  						_vector3.applyMatrix4( _projScreenMatrix );
 21158  
 21159  					}
 21160  
 21161  					pushRenderItem( object, null, object.material, _vector3.z, null );
 21162  
 21163  				} else if ( object.isMesh || object.isLine || object.isPoints ) {
 21164  
 21165  					if ( object.isSkinnedMesh ) {
 21166  
 21167  						object.skeleton.update();
 21168  
 21169  					}
 21170  
 21171  					if ( object.frustumCulled === false || isObjectViewable( object ) === true ) {
 21172  
 21173  						var material = object.material;
 21174  
 21175  						if ( material.visible === true ) {
 21176  
 21177  							if ( _this.sortObjects === true ) {
 21178  
 21179  								_vector3.setFromMatrixPosition( object.matrixWorld );
 21180  								_vector3.applyMatrix4( _projScreenMatrix );
 21181  
 21182  							}
 21183  
 21184  							var geometry = objects.update( object );
 21185  
 21186  							if ( material.isMultiMaterial ) {
 21187  
 21188  								var groups = geometry.groups;
 21189  								var materials = material.materials;
 21190  
 21191  								for ( var i = 0, l = groups.length; i < l; i ++ ) {
 21192  
 21193  									var group = groups[ i ];
 21194  									var groupMaterial = materials[ group.materialIndex ];
 21195  
 21196  									if ( groupMaterial.visible === true ) {
 21197  
 21198  										pushRenderItem( object, geometry, groupMaterial, _vector3.z, group );
 21199  
 21200  									}
 21201  
 21202  								}
 21203  
 21204  							} else {
 21205  
 21206  								pushRenderItem( object, geometry, material, _vector3.z, null );
 21207  
 21208  							}
 21209  
 21210  						}
 21211  
 21212  					}
 21213  
 21214  				}
 21215  
 21216  			}
 21217  
 21218  			var children = object.children;
 21219  
 21220  			for ( var i = 0, l = children.length; i < l; i ++ ) {
 21221  
 21222  				projectObject( children[ i ], camera );
 21223  
 21224  			}
 21225  
 21226  		}
 21227  
 21228  		function renderObjects( renderList, scene, camera, overrideMaterial ) {
 21229  
 21230  			for ( var i = 0, l = renderList.length; i < l; i ++ ) {
 21231  
 21232  				var renderItem = renderList[ i ];
 21233  
 21234  				var object = renderItem.object;
 21235  				var geometry = renderItem.geometry;
 21236  				var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial;
 21237  				var group = renderItem.group;
 21238  
 21239  				object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
 21240  				object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
 21241  
 21242  				object.onBeforeRender( _this, scene, camera, geometry, material, group );
 21243  
 21244  				if ( object.isImmediateRenderObject ) {
 21245  
 21246  					setMaterial( material );
 21247  
 21248  					var program = setProgram( camera, scene.fog, material, object );
 21249  
 21250  					_currentGeometryProgram = '';
 21251  
 21252  					object.render( function ( object ) {
 21253  
 21254  						_this.renderBufferImmediate( object, program, material );
 21255  
 21256  					} );
 21257  
 21258  				} else {
 21259  
 21260  					_this.renderBufferDirect( camera, scene.fog, geometry, material, object, group );
 21261  
 21262  				}
 21263  
 21264  				object.onAfterRender( _this, scene, camera, geometry, material, group );
 21265  
 21266  
 21267  			}
 21268  
 21269  		}
 21270  
 21271  		function initMaterial( material, fog, object ) {
 21272  
 21273  			var materialProperties = properties.get( material );
 21274  
 21275  			var parameters = programCache.getParameters(
 21276  				material, _lights, fog, _clipping.numPlanes, _clipping.numIntersection, object );
 21277  
 21278  			var code = programCache.getProgramCode( material, parameters );
 21279  
 21280  			var program = materialProperties.program;
 21281  			var programChange = true;
 21282  
 21283  			if ( program === undefined ) {
 21284  
 21285  				// new material
 21286  				material.addEventListener( 'dispose', onMaterialDispose );
 21287  
 21288  			} else if ( program.code !== code ) {
 21289  
 21290  				// changed glsl or parameters
 21291  				releaseMaterialProgramReference( material );
 21292  
 21293  			} else if ( parameters.shaderID !== undefined ) {
 21294  
 21295  				// same glsl and uniform list
 21296  				return;
 21297  
 21298  			} else {
 21299  
 21300  				// only rebuild uniform list
 21301  				programChange = false;
 21302  
 21303  			}
 21304  
 21305  			if ( programChange ) {
 21306  
 21307  				if ( parameters.shaderID ) {
 21308  
 21309  					var shader = ShaderLib[ parameters.shaderID ];
 21310  
 21311  					materialProperties.__webglShader = {
 21312  						name: material.type,
 21313  						uniforms: UniformsUtils.clone( shader.uniforms ),
 21314  						vertexShader: shader.vertexShader,
 21315  						fragmentShader: shader.fragmentShader
 21316  					};
 21317  
 21318  				} else {
 21319  
 21320  					materialProperties.__webglShader = {
 21321  						name: material.type,
 21322  						uniforms: material.uniforms,
 21323  						vertexShader: material.vertexShader,
 21324  						fragmentShader: material.fragmentShader
 21325  					};
 21326  
 21327  				}
 21328  
 21329  				material.__webglShader = materialProperties.__webglShader;
 21330  
 21331  				program = programCache.acquireProgram( material, parameters, code );
 21332  
 21333  				materialProperties.program = program;
 21334  				material.program = program;
 21335  
 21336  			}
 21337  
 21338  			var attributes = program.getAttributes();
 21339  
 21340  			if ( material.morphTargets ) {
 21341  
 21342  				material.numSupportedMorphTargets = 0;
 21343  
 21344  				for ( var i = 0; i < _this.maxMorphTargets; i ++ ) {
 21345  
 21346  					if ( attributes[ 'morphTarget' + i ] >= 0 ) {
 21347  
 21348  						material.numSupportedMorphTargets ++;
 21349  
 21350  					}
 21351  
 21352  				}
 21353  
 21354  			}
 21355  
 21356  			if ( material.morphNormals ) {
 21357  
 21358  				material.numSupportedMorphNormals = 0;
 21359  
 21360  				for ( var i = 0; i < _this.maxMorphNormals; i ++ ) {
 21361  
 21362  					if ( attributes[ 'morphNormal' + i ] >= 0 ) {
 21363  
 21364  						material.numSupportedMorphNormals ++;
 21365  
 21366  					}
 21367  
 21368  				}
 21369  
 21370  			}
 21371  
 21372  			var uniforms = materialProperties.__webglShader.uniforms;
 21373  
 21374  			if ( ! material.isShaderMaterial &&
 21375  				! material.isRawShaderMaterial ||
 21376  				material.clipping === true ) {
 21377  
 21378  				materialProperties.numClippingPlanes = _clipping.numPlanes;
 21379  				materialProperties.numIntersection = _clipping.numIntersection;
 21380  				uniforms.clippingPlanes = _clipping.uniform;
 21381  
 21382  			}
 21383  
 21384  			materialProperties.fog = fog;
 21385  
 21386  			// store the light setup it was created for
 21387  
 21388  			materialProperties.lightsHash = _lights.hash;
 21389  
 21390  			if ( material.lights ) {
 21391  
 21392  				// wire up the material to this renderer's lighting state
 21393  
 21394  				uniforms.ambientLightColor.value = _lights.ambient;
 21395  				uniforms.directionalLights.value = _lights.directional;
 21396  				uniforms.spotLights.value = _lights.spot;
 21397  				uniforms.rectAreaLights.value = _lights.rectArea;
 21398  				uniforms.pointLights.value = _lights.point;
 21399  				uniforms.hemisphereLights.value = _lights.hemi;
 21400  
 21401  				uniforms.directionalShadowMap.value = _lights.directionalShadowMap;
 21402  				uniforms.directionalShadowMatrix.value = _lights.directionalShadowMatrix;
 21403  				uniforms.spotShadowMap.value = _lights.spotShadowMap;
 21404  				uniforms.spotShadowMatrix.value = _lights.spotShadowMatrix;
 21405  				uniforms.pointShadowMap.value = _lights.pointShadowMap;
 21406  				uniforms.pointShadowMatrix.value = _lights.pointShadowMatrix;
 21407  				// TODO (abelnation): add area lights shadow info to uniforms
 21408  
 21409  			}
 21410  
 21411  			var progUniforms = materialProperties.program.getUniforms(),
 21412  				uniformsList =
 21413  					WebGLUniforms.seqWithValue( progUniforms.seq, uniforms );
 21414  
 21415  			materialProperties.uniformsList = uniformsList;
 21416  
 21417  		}
 21418  
 21419  		function setMaterial( material ) {
 21420  
 21421  			material.side === DoubleSide
 21422  				? state.disable( _gl.CULL_FACE )
 21423  				: state.enable( _gl.CULL_FACE );
 21424  
 21425  			state.setFlipSided( material.side === BackSide );
 21426  
 21427  			material.transparent === true
 21428  				? state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha )
 21429  				: state.setBlending( NoBlending );
 21430  
 21431  			state.setDepthFunc( material.depthFunc );
 21432  			state.setDepthTest( material.depthTest );
 21433  			state.setDepthWrite( material.depthWrite );
 21434  			state.setColorWrite( material.colorWrite );
 21435  			state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
 21436  
 21437  		}
 21438  
 21439  		function setProgram( camera, fog, material, object ) {
 21440  
 21441  			_usedTextureUnits = 0;
 21442  
 21443  			var materialProperties = properties.get( material );
 21444  
 21445  			if ( _clippingEnabled ) {
 21446  
 21447  				if ( _localClippingEnabled || camera !== _currentCamera ) {
 21448  
 21449  					var useCache =
 21450  						camera === _currentCamera &&
 21451  						material.id === _currentMaterialId;
 21452  
 21453  					// we might want to call this function with some ClippingGroup
 21454  					// object instead of the material, once it becomes feasible
 21455  					// (#8465, #8379)
 21456  					_clipping.setState(
 21457  						material.clippingPlanes, material.clipIntersection, material.clipShadows,
 21458  						camera, materialProperties, useCache );
 21459  
 21460  				}
 21461  
 21462  			}
 21463  
 21464  			if ( material.needsUpdate === false ) {
 21465  
 21466  				if ( materialProperties.program === undefined ) {
 21467  
 21468  					material.needsUpdate = true;
 21469  
 21470  				} else if ( material.fog && materialProperties.fog !== fog ) {
 21471  
 21472  					material.needsUpdate = true;
 21473  
 21474  				} else if ( material.lights && materialProperties.lightsHash !== _lights.hash ) {
 21475  
 21476  					material.needsUpdate = true;
 21477  
 21478  				} else if ( materialProperties.numClippingPlanes !== undefined &&
 21479  					( materialProperties.numClippingPlanes !== _clipping.numPlanes ||
 21480  					materialProperties.numIntersection  !== _clipping.numIntersection ) ) {
 21481  
 21482  					material.needsUpdate = true;
 21483  
 21484  				}
 21485  
 21486  			}
 21487  
 21488  			if ( material.needsUpdate ) {
 21489  
 21490  				initMaterial( material, fog, object );
 21491  				material.needsUpdate = false;
 21492  
 21493  			}
 21494  
 21495  			var refreshProgram = false;
 21496  			var refreshMaterial = false;
 21497  			var refreshLights = false;
 21498  
 21499  			var program = materialProperties.program,
 21500  				p_uniforms = program.getUniforms(),
 21501  				m_uniforms = materialProperties.__webglShader.uniforms;
 21502  
 21503  			if ( program.id !== _currentProgram ) {
 21504  
 21505  				_gl.useProgram( program.program );
 21506  				_currentProgram = program.id;
 21507  
 21508  				refreshProgram = true;
 21509  				refreshMaterial = true;
 21510  				refreshLights = true;
 21511  
 21512  			}
 21513  
 21514  			if ( material.id !== _currentMaterialId ) {
 21515  
 21516  				_currentMaterialId = material.id;
 21517  
 21518  				refreshMaterial = true;
 21519  
 21520  			}
 21521  
 21522  			if ( refreshProgram || camera !== _currentCamera ) {
 21523  
 21524  				p_uniforms.set( _gl, camera, 'projectionMatrix' );
 21525  
 21526  				if ( capabilities.logarithmicDepthBuffer ) {
 21527  
 21528  					p_uniforms.setValue( _gl, 'logDepthBufFC',
 21529  						2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
 21530  
 21531  				}
 21532  
 21533  
 21534  				if ( camera !== _currentCamera ) {
 21535  
 21536  					_currentCamera = camera;
 21537  
 21538  					// lighting uniforms depend on the camera so enforce an update
 21539  					// now, in case this material supports lights - or later, when
 21540  					// the next material that does gets activated:
 21541  
 21542  					refreshMaterial = true;		// set to true on material change
 21543  					refreshLights = true;		// remains set until update done
 21544  
 21545  				}
 21546  
 21547  				// load material specific uniforms
 21548  				// (shader material also gets them for the sake of genericity)
 21549  
 21550  				if ( material.isShaderMaterial ||
 21551  					material.isMeshPhongMaterial ||
 21552  					material.isMeshStandardMaterial ||
 21553  					material.envMap ) {
 21554  
 21555  					var uCamPos = p_uniforms.map.cameraPosition;
 21556  
 21557  					if ( uCamPos !== undefined ) {
 21558  
 21559  						uCamPos.setValue( _gl,
 21560  							_vector3.setFromMatrixPosition( camera.matrixWorld ) );
 21561  
 21562  					}
 21563  
 21564  				}
 21565  
 21566  				if ( material.isMeshPhongMaterial ||
 21567  					material.isMeshLambertMaterial ||
 21568  					material.isMeshBasicMaterial ||
 21569  					material.isMeshStandardMaterial ||
 21570  					material.isShaderMaterial ||
 21571  					material.skinning ) {
 21572  
 21573  					p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
 21574  
 21575  				}
 21576  
 21577  				p_uniforms.set( _gl, _this, 'toneMappingExposure' );
 21578  				p_uniforms.set( _gl, _this, 'toneMappingWhitePoint' );
 21579  
 21580  			}
 21581  
 21582  			// skinning uniforms must be set even if material didn't change
 21583  			// auto-setting of texture unit for bone texture must go before other textures
 21584  			// not sure why, but otherwise weird things happen
 21585  
 21586  			if ( material.skinning ) {
 21587  
 21588  				p_uniforms.setOptional( _gl, object, 'bindMatrix' );
 21589  				p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
 21590  
 21591  				var skeleton = object.skeleton;
 21592  
 21593  				if ( skeleton ) {
 21594  
 21595  					if ( capabilities.floatVertexTextures && skeleton.useVertexTexture ) {
 21596  
 21597  						p_uniforms.set( _gl, skeleton, 'boneTexture' );
 21598  						p_uniforms.set( _gl, skeleton, 'boneTextureWidth' );
 21599  						p_uniforms.set( _gl, skeleton, 'boneTextureHeight' );
 21600  
 21601  					} else {
 21602  
 21603  						p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' );
 21604  
 21605  					}
 21606  
 21607  				}
 21608  
 21609  			}
 21610  
 21611  			if ( refreshMaterial ) {
 21612  
 21613  				if ( material.lights ) {
 21614  
 21615  					// the current material requires lighting info
 21616  
 21617  					// note: all lighting uniforms are always set correctly
 21618  					// they simply reference the renderer's state for their
 21619  					// values
 21620  					//
 21621  					// use the current material's .needsUpdate flags to set
 21622  					// the GL state when required
 21623  
 21624  					markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );
 21625  
 21626  				}
 21627  
 21628  				// refresh uniforms common to several materials
 21629  
 21630  				if ( fog && material.fog ) {
 21631  
 21632  					refreshUniformsFog( m_uniforms, fog );
 21633  
 21634  				}
 21635  
 21636  				if ( material.isMeshBasicMaterial ||
 21637  					material.isMeshLambertMaterial ||
 21638  					material.isMeshPhongMaterial ||
 21639  					material.isMeshStandardMaterial ||
 21640  					material.isMeshNormalMaterial ||
 21641  					material.isMeshDepthMaterial ) {
 21642  
 21643  					refreshUniformsCommon( m_uniforms, material );
 21644  
 21645  				}
 21646  
 21647  				// refresh single material specific uniforms
 21648  
 21649  				if ( material.isLineBasicMaterial ) {
 21650  
 21651  					refreshUniformsLine( m_uniforms, material );
 21652  
 21653  				} else if ( material.isLineDashedMaterial ) {
 21654  
 21655  					refreshUniformsLine( m_uniforms, material );
 21656  					refreshUniformsDash( m_uniforms, material );
 21657  
 21658  				} else if ( material.isPointsMaterial ) {
 21659  
 21660  					refreshUniformsPoints( m_uniforms, material );
 21661  
 21662  				} else if ( material.isMeshLambertMaterial ) {
 21663  
 21664  					refreshUniformsLambert( m_uniforms, material );
 21665  
 21666  				} else if ( material.isMeshToonMaterial ) {
 21667  
 21668  					refreshUniformsToon( m_uniforms, material );
 21669  
 21670  				} else if ( material.isMeshPhongMaterial ) {
 21671  
 21672  					refreshUniformsPhong( m_uniforms, material );
 21673  
 21674  				} else if ( material.isMeshPhysicalMaterial ) {
 21675  
 21676  					refreshUniformsPhysical( m_uniforms, material );
 21677  
 21678  				} else if ( material.isMeshStandardMaterial ) {
 21679  
 21680  					refreshUniformsStandard( m_uniforms, material );
 21681  
 21682  				} else if ( material.isMeshDepthMaterial ) {
 21683  
 21684  					if ( material.displacementMap ) {
 21685  
 21686  						m_uniforms.displacementMap.value = material.displacementMap;
 21687  						m_uniforms.displacementScale.value = material.displacementScale;
 21688  						m_uniforms.displacementBias.value = material.displacementBias;
 21689  
 21690  					}
 21691  
 21692  				} else if ( material.isMeshNormalMaterial ) {
 21693  
 21694  					refreshUniformsNormal( m_uniforms, material );
 21695  
 21696  				}
 21697  
 21698  				// RectAreaLight Texture
 21699  				// TODO (mrdoob): Find a nicer implementation
 21700  
 21701  				if ( m_uniforms.ltcMat !== undefined ) m_uniforms.ltcMat.value = THREE.UniformsLib.LTC_MAT_TEXTURE;
 21702  				if ( m_uniforms.ltcMag !== undefined ) m_uniforms.ltcMag.value = THREE.UniformsLib.LTC_MAG_TEXTURE;
 21703  
 21704  				WebGLUniforms.upload(
 21705  					_gl, materialProperties.uniformsList, m_uniforms, _this );
 21706  
 21707  			}
 21708  
 21709  
 21710  			// common matrices
 21711  
 21712  			p_uniforms.set( _gl, object, 'modelViewMatrix' );
 21713  			p_uniforms.set( _gl, object, 'normalMatrix' );
 21714  			p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
 21715  
 21716  			return program;
 21717  
 21718  		}
 21719  
 21720  		// Uniforms (refresh uniforms objects)
 21721  
 21722  		function refreshUniformsCommon( uniforms, material ) {
 21723  
 21724  			uniforms.opacity.value = material.opacity;
 21725  
 21726  			uniforms.diffuse.value = material.color;
 21727  
 21728  			if ( material.emissive ) {
 21729  
 21730  				uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
 21731  
 21732  			}
 21733  
 21734  			uniforms.map.value = material.map;
 21735  			uniforms.specularMap.value = material.specularMap;
 21736  			uniforms.alphaMap.value = material.alphaMap;
 21737  
 21738  			if ( material.lightMap ) {
 21739  
 21740  				uniforms.lightMap.value = material.lightMap;
 21741  				uniforms.lightMapIntensity.value = material.lightMapIntensity;
 21742  
 21743  			}
 21744  
 21745  			if ( material.aoMap ) {
 21746  
 21747  				uniforms.aoMap.value = material.aoMap;
 21748  				uniforms.aoMapIntensity.value = material.aoMapIntensity;
 21749  
 21750  			}
 21751  
 21752  			// uv repeat and offset setting priorities
 21753  			// 1. color map
 21754  			// 2. specular map
 21755  			// 3. normal map
 21756  			// 4. bump map
 21757  			// 5. alpha map
 21758  			// 6. emissive map
 21759  
 21760  			var uvScaleMap;
 21761  
 21762  			if ( material.map ) {
 21763  
 21764  				uvScaleMap = material.map;
 21765  
 21766  			} else if ( material.specularMap ) {
 21767  
 21768  				uvScaleMap = material.specularMap;
 21769  
 21770  			} else if ( material.displacementMap ) {
 21771  
 21772  				uvScaleMap = material.displacementMap;
 21773  
 21774  			} else if ( material.normalMap ) {
 21775  
 21776  				uvScaleMap = material.normalMap;
 21777  
 21778  			} else if ( material.bumpMap ) {
 21779  
 21780  				uvScaleMap = material.bumpMap;
 21781  
 21782  			} else if ( material.roughnessMap ) {
 21783  
 21784  				uvScaleMap = material.roughnessMap;
 21785  
 21786  			} else if ( material.metalnessMap ) {
 21787  
 21788  				uvScaleMap = material.metalnessMap;
 21789  
 21790  			} else if ( material.alphaMap ) {
 21791  
 21792  				uvScaleMap = material.alphaMap;
 21793  
 21794  			} else if ( material.emissiveMap ) {
 21795  
 21796  				uvScaleMap = material.emissiveMap;
 21797  
 21798  			}
 21799  
 21800  			if ( uvScaleMap !== undefined ) {
 21801  
 21802  				// backwards compatibility
 21803  				if ( uvScaleMap.isWebGLRenderTarget ) {
 21804  
 21805  					uvScaleMap = uvScaleMap.texture;
 21806  
 21807  				}
 21808  
 21809  				var offset = uvScaleMap.offset;
 21810  				var repeat = uvScaleMap.repeat;
 21811  
 21812  				uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
 21813  
 21814  			}
 21815  
 21816  			uniforms.envMap.value = material.envMap;
 21817  
 21818  			// don't flip CubeTexture envMaps, flip everything else:
 21819  			//  WebGLRenderTargetCube will be flipped for backwards compatibility
 21820  			//  WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture
 21821  			// this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future
 21822  			uniforms.flipEnvMap.value = ( ! ( material.envMap && material.envMap.isCubeTexture ) ) ? 1 : - 1;
 21823  
 21824  			uniforms.reflectivity.value = material.reflectivity;
 21825  			uniforms.refractionRatio.value = material.refractionRatio;
 21826  
 21827  		}
 21828  
 21829  		function refreshUniformsLine( uniforms, material ) {
 21830  
 21831  			uniforms.diffuse.value = material.color;
 21832  			uniforms.opacity.value = material.opacity;
 21833  
 21834  		}
 21835  
 21836  		function refreshUniformsDash( uniforms, material ) {
 21837  
 21838  			uniforms.dashSize.value = material.dashSize;
 21839  			uniforms.totalSize.value = material.dashSize + material.gapSize;
 21840  			uniforms.scale.value = material.scale;
 21841  
 21842  		}
 21843  
 21844  		function refreshUniformsPoints( uniforms, material ) {
 21845  
 21846  			uniforms.diffuse.value = material.color;
 21847  			uniforms.opacity.value = material.opacity;
 21848  			uniforms.size.value = material.size * _pixelRatio;
 21849  			uniforms.scale.value = _height * 0.5;
 21850  
 21851  			uniforms.map.value = material.map;
 21852  
 21853  			if ( material.map !== null ) {
 21854  
 21855  				var offset = material.map.offset;
 21856  				var repeat = material.map.repeat;
 21857  
 21858  				uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
 21859  
 21860  			}
 21861  
 21862  		}
 21863  
 21864  		function refreshUniformsFog( uniforms, fog ) {
 21865  
 21866  			uniforms.fogColor.value = fog.color;
 21867  
 21868  			if ( fog.isFog ) {
 21869  
 21870  				uniforms.fogNear.value = fog.near;
 21871  				uniforms.fogFar.value = fog.far;
 21872  
 21873  			} else if ( fog.isFogExp2 ) {
 21874  
 21875  				uniforms.fogDensity.value = fog.density;
 21876  
 21877  			}
 21878  
 21879  		}
 21880  
 21881  		function refreshUniformsLambert( uniforms, material ) {
 21882  
 21883  			if ( material.emissiveMap ) {
 21884  
 21885  				uniforms.emissiveMap.value = material.emissiveMap;
 21886  
 21887  			}
 21888  
 21889  		}
 21890  
 21891  		function refreshUniformsPhong( uniforms, material ) {
 21892  
 21893  			uniforms.specular.value = material.specular;
 21894  			uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
 21895  
 21896  			if ( material.emissiveMap ) {
 21897  
 21898  				uniforms.emissiveMap.value = material.emissiveMap;
 21899  
 21900  			}
 21901  
 21902  			if ( material.bumpMap ) {
 21903  
 21904  				uniforms.bumpMap.value = material.bumpMap;
 21905  				uniforms.bumpScale.value = material.bumpScale;
 21906  
 21907  			}
 21908  
 21909  			if ( material.normalMap ) {
 21910  
 21911  				uniforms.normalMap.value = material.normalMap;
 21912  				uniforms.normalScale.value.copy( material.normalScale );
 21913  
 21914  			}
 21915  
 21916  			if ( material.displacementMap ) {
 21917  
 21918  				uniforms.displacementMap.value = material.displacementMap;
 21919  				uniforms.displacementScale.value = material.displacementScale;
 21920  				uniforms.displacementBias.value = material.displacementBias;
 21921  
 21922  			}
 21923  
 21924  		}
 21925  
 21926  		function refreshUniformsToon( uniforms, material ) {
 21927  
 21928  			refreshUniformsPhong( uniforms, material );
 21929  
 21930  			if ( material.gradientMap ) {
 21931  
 21932  				uniforms.gradientMap.value = material.gradientMap;
 21933  
 21934  			}
 21935  
 21936  		}
 21937  
 21938  		function refreshUniformsStandard( uniforms, material ) {
 21939  
 21940  			uniforms.roughness.value = material.roughness;
 21941  			uniforms.metalness.value = material.metalness;
 21942  
 21943  			if ( material.roughnessMap ) {
 21944  
 21945  				uniforms.roughnessMap.value = material.roughnessMap;
 21946  
 21947  			}
 21948  
 21949  			if ( material.metalnessMap ) {
 21950  
 21951  				uniforms.metalnessMap.value = material.metalnessMap;
 21952  
 21953  			}
 21954  
 21955  			if ( material.emissiveMap ) {
 21956  
 21957  				uniforms.emissiveMap.value = material.emissiveMap;
 21958  
 21959  			}
 21960  
 21961  			if ( material.bumpMap ) {
 21962  
 21963  				uniforms.bumpMap.value = material.bumpMap;
 21964  				uniforms.bumpScale.value = material.bumpScale;
 21965  
 21966  			}
 21967  
 21968  			if ( material.normalMap ) {
 21969  
 21970  				uniforms.normalMap.value = material.normalMap;
 21971  				uniforms.normalScale.value.copy( material.normalScale );
 21972  
 21973  			}
 21974  
 21975  			if ( material.displacementMap ) {
 21976  
 21977  				uniforms.displacementMap.value = material.displacementMap;
 21978  				uniforms.displacementScale.value = material.displacementScale;
 21979  				uniforms.displacementBias.value = material.displacementBias;
 21980  
 21981  			}
 21982  
 21983  			if ( material.envMap ) {
 21984  
 21985  				//uniforms.envMap.value = material.envMap; // part of uniforms common
 21986  				uniforms.envMapIntensity.value = material.envMapIntensity;
 21987  
 21988  			}
 21989  
 21990  		}
 21991  
 21992  		function refreshUniformsPhysical( uniforms, material ) {
 21993  
 21994  			uniforms.clearCoat.value = material.clearCoat;
 21995  			uniforms.clearCoatRoughness.value = material.clearCoatRoughness;
 21996  
 21997  			refreshUniformsStandard( uniforms, material );
 21998  
 21999  		}
 22000  
 22001  		function refreshUniformsNormal( uniforms, material ) {
 22002  
 22003  			if ( material.bumpMap ) {
 22004  
 22005  				uniforms.bumpMap.value = material.bumpMap;
 22006  				uniforms.bumpScale.value = material.bumpScale;
 22007  
 22008  			}
 22009  
 22010  			if ( material.normalMap ) {
 22011  
 22012  				uniforms.normalMap.value = material.normalMap;
 22013  				uniforms.normalScale.value.copy( material.normalScale );
 22014  
 22015  			}
 22016  
 22017  			if ( material.displacementMap ) {
 22018  
 22019  				uniforms.displacementMap.value = material.displacementMap;
 22020  				uniforms.displacementScale.value = material.displacementScale;
 22021  				uniforms.displacementBias.value = material.displacementBias;
 22022  
 22023  			}
 22024  
 22025  		}
 22026  
 22027  		// If uniforms are marked as clean, they don't need to be loaded to the GPU.
 22028  
 22029  		function markUniformsLightsNeedsUpdate( uniforms, value ) {
 22030  
 22031  			uniforms.ambientLightColor.needsUpdate = value;
 22032  
 22033  			uniforms.directionalLights.needsUpdate = value;
 22034  			uniforms.pointLights.needsUpdate = value;
 22035  			uniforms.spotLights.needsUpdate = value;
 22036  			uniforms.rectAreaLights.needsUpdate = value;
 22037  			uniforms.hemisphereLights.needsUpdate = value;
 22038  
 22039  		}
 22040  
 22041  		// Lighting
 22042  
 22043  		function setupShadows( lights ) {
 22044  
 22045  			var lightShadowsLength = 0;
 22046  
 22047  			for ( var i = 0, l = lights.length; i < l; i ++ ) {
 22048  
 22049  				var light = lights[ i ];
 22050  
 22051  				if ( light.castShadow ) {
 22052  
 22053  					_lights.shadows[ lightShadowsLength ++ ] = light;
 22054  
 22055  				}
 22056  
 22057  			}
 22058  
 22059  			_lights.shadows.length = lightShadowsLength;
 22060  
 22061  		}
 22062  
 22063  		function setupLights( lights, camera ) {
 22064  
 22065  			var l, ll, light,
 22066  				r = 0, g = 0, b = 0,
 22067  				color,
 22068  				intensity,
 22069  				distance,
 22070  				shadowMap,
 22071  
 22072  				viewMatrix = camera.matrixWorldInverse,
 22073  
 22074  			directionalLength = 0,
 22075  			pointLength = 0,
 22076  			spotLength = 0,
 22077  			rectAreaLength = 0,
 22078  			hemiLength = 0;
 22079  
 22080  			for ( l = 0, ll = lights.length; l < ll; l ++ ) {
 22081  
 22082  				light = lights[ l ];
 22083  
 22084  				color = light.color;
 22085  				intensity = light.intensity;
 22086  				distance = light.distance;
 22087  
 22088  				shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;
 22089  
 22090  				if ( light.isAmbientLight ) {
 22091  
 22092  					r += color.r * intensity;
 22093  					g += color.g * intensity;
 22094  					b += color.b * intensity;
 22095  
 22096  				} else if ( light.isDirectionalLight ) {
 22097  
 22098  					var uniforms = lightCache.get( light );
 22099  
 22100  					uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
 22101  					uniforms.direction.setFromMatrixPosition( light.matrixWorld );
 22102  					_vector3.setFromMatrixPosition( light.target.matrixWorld );
 22103  					uniforms.direction.sub( _vector3 );
 22104  					uniforms.direction.transformDirection( viewMatrix );
 22105  
 22106  					uniforms.shadow = light.castShadow;
 22107  
 22108  					if ( light.castShadow ) {
 22109  
 22110  						uniforms.shadowBias = light.shadow.bias;
 22111  						uniforms.shadowRadius = light.shadow.radius;
 22112  						uniforms.shadowMapSize = light.shadow.mapSize;
 22113  
 22114  					}
 22115  
 22116  					_lights.directionalShadowMap[ directionalLength ] = shadowMap;
 22117  					_lights.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
 22118  					_lights.directional[ directionalLength ++ ] = uniforms;
 22119  
 22120  				} else if ( light.isSpotLight ) {
 22121  
 22122  					var uniforms = lightCache.get( light );
 22123  
 22124  					uniforms.position.setFromMatrixPosition( light.matrixWorld );
 22125  					uniforms.position.applyMatrix4( viewMatrix );
 22126  
 22127  					uniforms.color.copy( color ).multiplyScalar( intensity );
 22128  					uniforms.distance = distance;
 22129  
 22130  					uniforms.direction.setFromMatrixPosition( light.matrixWorld );
 22131  					_vector3.setFromMatrixPosition( light.target.matrixWorld );
 22132  					uniforms.direction.sub( _vector3 );
 22133  					uniforms.direction.transformDirection( viewMatrix );
 22134  
 22135  					uniforms.coneCos = Math.cos( light.angle );
 22136  					uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
 22137  					uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;
 22138  
 22139  					uniforms.shadow = light.castShadow;
 22140  
 22141  					if ( light.castShadow ) {
 22142  
 22143  						uniforms.shadowBias = light.shadow.bias;
 22144  						uniforms.shadowRadius = light.shadow.radius;
 22145  						uniforms.shadowMapSize = light.shadow.mapSize;
 22146  
 22147  					}
 22148  
 22149  					_lights.spotShadowMap[ spotLength ] = shadowMap;
 22150  					_lights.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
 22151  					_lights.spot[ spotLength ++ ] = uniforms;
 22152  
 22153  				} else if ( light.isRectAreaLight ) {
 22154  
 22155  					var uniforms = lightCache.get( light );
 22156  
 22157  					// (a) intensity controls irradiance of entire light
 22158  					uniforms.color
 22159  						.copy( color )
 22160  						.multiplyScalar( intensity / ( light.width * light.height ) );
 22161  
 22162  					// (b) intensity controls the radiance per light area
 22163  					// uniforms.color.copy( color ).multiplyScalar( intensity );
 22164  
 22165  					uniforms.position.setFromMatrixPosition( light.matrixWorld );
 22166  					uniforms.position.applyMatrix4( viewMatrix );
 22167  
 22168  					// extract local rotation of light to derive width/height half vectors
 22169  					_matrix42.identity();
 22170  					_matrix4.copy( light.matrixWorld );
 22171  					_matrix4.premultiply( viewMatrix );
 22172  					_matrix42.extractRotation( _matrix4 );
 22173  
 22174  					uniforms.halfWidth.set( light.width * 0.5,                0.0, 0.0 );
 22175  					uniforms.halfHeight.set(              0.0, light.height * 0.5, 0.0 );
 22176  
 22177  					uniforms.halfWidth.applyMatrix4( _matrix42 );
 22178  					uniforms.halfHeight.applyMatrix4( _matrix42 );
 22179  
 22180  					// TODO (abelnation): RectAreaLight distance?
 22181  					// uniforms.distance = distance;
 22182  
 22183  					_lights.rectArea[ rectAreaLength ++ ] = uniforms;
 22184  
 22185  				} else if ( light.isPointLight ) {
 22186  
 22187  					var uniforms = lightCache.get( light );
 22188  
 22189  					uniforms.position.setFromMatrixPosition( light.matrixWorld );
 22190  					uniforms.position.applyMatrix4( viewMatrix );
 22191  
 22192  					uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
 22193  					uniforms.distance = light.distance;
 22194  					uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;
 22195  
 22196  					uniforms.shadow = light.castShadow;
 22197  
 22198  					if ( light.castShadow ) {
 22199  
 22200  						uniforms.shadowBias = light.shadow.bias;
 22201  						uniforms.shadowRadius = light.shadow.radius;
 22202  						uniforms.shadowMapSize = light.shadow.mapSize;
 22203  
 22204  					}
 22205  
 22206  					_lights.pointShadowMap[ pointLength ] = shadowMap;
 22207  
 22208  					if ( _lights.pointShadowMatrix[ pointLength ] === undefined ) {
 22209  
 22210  						_lights.pointShadowMatrix[ pointLength ] = new Matrix4();
 22211  
 22212  					}
 22213  
 22214  					// for point lights we set the shadow matrix to be a translation-only matrix
 22215  					// equal to inverse of the light's position
 22216  					_vector3.setFromMatrixPosition( light.matrixWorld ).negate();
 22217  					_lights.pointShadowMatrix[ pointLength ].identity().setPosition( _vector3 );
 22218  
 22219  					_lights.point[ pointLength ++ ] = uniforms;
 22220  
 22221  				} else if ( light.isHemisphereLight ) {
 22222  
 22223  					var uniforms = lightCache.get( light );
 22224  
 22225  					uniforms.direction.setFromMatrixPosition( light.matrixWorld );
 22226  					uniforms.direction.transformDirection( viewMatrix );
 22227  					uniforms.direction.normalize();
 22228  
 22229  					uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
 22230  					uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );
 22231  
 22232  					_lights.hemi[ hemiLength ++ ] = uniforms;
 22233  
 22234  				}
 22235  
 22236  			}
 22237  
 22238  			_lights.ambient[ 0 ] = r;
 22239  			_lights.ambient[ 1 ] = g;
 22240  			_lights.ambient[ 2 ] = b;
 22241  
 22242  			_lights.directional.length = directionalLength;
 22243  			_lights.spot.length = spotLength;
 22244  			_lights.rectArea.length = rectAreaLength;
 22245  			_lights.point.length = pointLength;
 22246  			_lights.hemi.length = hemiLength;
 22247  
 22248  			// TODO (sam-g-steel) why aren't we using join
 22249  			_lights.hash = directionalLength + ',' + pointLength + ',' + spotLength + ',' + rectAreaLength + ',' + hemiLength + ',' + _lights.shadows.length;
 22250  
 22251  		}
 22252  
 22253  		// GL state setting
 22254  
 22255  		this.setFaceCulling = function ( cullFace, frontFaceDirection ) {
 22256  
 22257  			state.setCullFace( cullFace );
 22258  			state.setFlipSided( frontFaceDirection === FrontFaceDirectionCW );
 22259  
 22260  		};
 22261  
 22262  		// Textures
 22263  
 22264  		function allocTextureUnit() {
 22265  
 22266  			var textureUnit = _usedTextureUnits;
 22267  
 22268  			if ( textureUnit >= capabilities.maxTextures ) {
 22269  
 22270  				console.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );
 22271  
 22272  			}
 22273  
 22274  			_usedTextureUnits += 1;
 22275  
 22276  			return textureUnit;
 22277  
 22278  		}
 22279  
 22280  		this.allocTextureUnit = allocTextureUnit;
 22281  
 22282  		// this.setTexture2D = setTexture2D;
 22283  		this.setTexture2D = ( function() {
 22284  
 22285  			var warned = false;
 22286  
 22287  			// backwards compatibility: peel texture.texture
 22288  			return function setTexture2D( texture, slot ) {
 22289  
 22290  				if ( texture && texture.isWebGLRenderTarget ) {
 22291  
 22292  					if ( ! warned ) {
 22293  
 22294  						console.warn( "THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead." );
 22295  						warned = true;
 22296  
 22297  					}
 22298  
 22299  					texture = texture.texture;
 22300  
 22301  				}
 22302  
 22303  				textures.setTexture2D( texture, slot );
 22304  
 22305  			};
 22306  
 22307  		}() );
 22308  
 22309  		this.setTexture = ( function() {
 22310  
 22311  			var warned = false;
 22312  
 22313  			return function setTexture( texture, slot ) {
 22314  
 22315  				if ( ! warned ) {
 22316  
 22317  					console.warn( "THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead." );
 22318  					warned = true;
 22319  
 22320  				}
 22321  
 22322  				textures.setTexture2D( texture, slot );
 22323  
 22324  			};
 22325  
 22326  		}() );
 22327  
 22328  		this.setTextureCube = ( function() {
 22329  
 22330  			var warned = false;
 22331  
 22332  			return function setTextureCube( texture, slot ) {
 22333  
 22334  				// backwards compatibility: peel texture.texture
 22335  				if ( texture && texture.isWebGLRenderTargetCube ) {
 22336  
 22337  					if ( ! warned ) {
 22338  
 22339  						console.warn( "THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead." );
 22340  						warned = true;
 22341  
 22342  					}
 22343  
 22344  					texture = texture.texture;
 22345  
 22346  				}
 22347  
 22348  				// currently relying on the fact that WebGLRenderTargetCube.texture is a Texture and NOT a CubeTexture
 22349  				// TODO: unify these code paths
 22350  				if ( ( texture && texture.isCubeTexture ) ||
 22351  					( Array.isArray( texture.image ) && texture.image.length === 6 ) ) {
 22352  
 22353  					// CompressedTexture can have Array in image :/
 22354  
 22355  					// this function alone should take care of cube textures
 22356  					textures.setTextureCube( texture, slot );
 22357  
 22358  				} else {
 22359  
 22360  					// assumed: texture property of THREE.WebGLRenderTargetCube
 22361  
 22362  					textures.setTextureCubeDynamic( texture, slot );
 22363  
 22364  				}
 22365  
 22366  			};
 22367  
 22368  		}() );
 22369  
 22370  		this.getCurrentRenderTarget = function() {
 22371  
 22372  			return _currentRenderTarget;
 22373  
 22374  		};
 22375  
 22376  		this.setRenderTarget = function ( renderTarget ) {
 22377  
 22378  			_currentRenderTarget = renderTarget;
 22379  
 22380  			if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {
 22381  
 22382  				textures.setupRenderTarget( renderTarget );
 22383  
 22384  			}
 22385  
 22386  			var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube );
 22387  			var framebuffer;
 22388  
 22389  			if ( renderTarget ) {
 22390  
 22391  				var renderTargetProperties = properties.get( renderTarget );
 22392  
 22393  				if ( isCube ) {
 22394  
 22395  					framebuffer = renderTargetProperties.__webglFramebuffer[ renderTarget.activeCubeFace ];
 22396  
 22397  				} else {
 22398  
 22399  					framebuffer = renderTargetProperties.__webglFramebuffer;
 22400  
 22401  				}
 22402  
 22403  				_currentScissor.copy( renderTarget.scissor );
 22404  				_currentScissorTest = renderTarget.scissorTest;
 22405  
 22406  				_currentViewport.copy( renderTarget.viewport );
 22407  
 22408  			} else {
 22409  
 22410  				framebuffer = null;
 22411  
 22412  				_currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio );
 22413  				_currentScissorTest = _scissorTest;
 22414  
 22415  				_currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio );
 22416  
 22417  			}
 22418  
 22419  			if ( _currentFramebuffer !== framebuffer ) {
 22420  
 22421  				_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
 22422  				_currentFramebuffer = framebuffer;
 22423  
 22424  			}
 22425  
 22426  			state.scissor( _currentScissor );
 22427  			state.setScissorTest( _currentScissorTest );
 22428  
 22429  			state.viewport( _currentViewport );
 22430  
 22431  			if ( isCube ) {
 22432  
 22433  				var textureProperties = properties.get( renderTarget.texture );
 22434  				_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel );
 22435  
 22436  			}
 22437  
 22438  		};
 22439  
 22440  		this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) {
 22441  
 22442  			if ( ( renderTarget && renderTarget.isWebGLRenderTarget ) === false ) {
 22443  
 22444  				console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
 22445  				return;
 22446  
 22447  			}
 22448  
 22449  			var framebuffer = properties.get( renderTarget ).__webglFramebuffer;
 22450  
 22451  			if ( framebuffer ) {
 22452  
 22453  				var restore = false;
 22454  
 22455  				if ( framebuffer !== _currentFramebuffer ) {
 22456  
 22457  					_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
 22458  
 22459  					restore = true;
 22460  
 22461  				}
 22462  
 22463  				try {
 22464  
 22465  					var texture = renderTarget.texture;
 22466  					var textureFormat = texture.format;
 22467  					var textureType = texture.type;
 22468  
 22469  					if ( textureFormat !== RGBAFormat && paramThreeToGL( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
 22470  
 22471  						console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
 22472  						return;
 22473  
 22474  					}
 22475  
 22476  					if ( textureType !== UnsignedByteType && paramThreeToGL( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // IE11, Edge and Chrome Mac < 52 (#9513)
 22477  						! ( textureType === FloatType && ( extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
 22478  						! ( textureType === HalfFloatType && extensions.get( 'EXT_color_buffer_half_float' ) ) ) {
 22479  
 22480  						console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
 22481  						return;
 22482  
 22483  					}
 22484  
 22485  					if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) {
 22486  
 22487  						// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
 22488  
 22489  						if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
 22490  
 22491  							_gl.readPixels( x, y, width, height, paramThreeToGL( textureFormat ), paramThreeToGL( textureType ), buffer );
 22492  
 22493  						}
 22494  
 22495  					} else {
 22496  
 22497  						console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );
 22498  
 22499  					}
 22500  
 22501  				} finally {
 22502  
 22503  					if ( restore ) {
 22504  
 22505  						_gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );
 22506  
 22507  					}
 22508  
 22509  				}
 22510  
 22511  			}
 22512  
 22513  		};
 22514  
 22515  		// Map three.js constants to WebGL constants
 22516  
 22517  		function paramThreeToGL( p ) {
 22518  
 22519  			var extension;
 22520  
 22521  			if ( p === RepeatWrapping ) return _gl.REPEAT;
 22522  			if ( p === ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;
 22523  			if ( p === MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;
 22524  
 22525  			if ( p === NearestFilter ) return _gl.NEAREST;
 22526  			if ( p === NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;
 22527  			if ( p === NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;
 22528  
 22529  			if ( p === LinearFilter ) return _gl.LINEAR;
 22530  			if ( p === LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;
 22531  			if ( p === LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;
 22532  
 22533  			if ( p === UnsignedByteType ) return _gl.UNSIGNED_BYTE;
 22534  			if ( p === UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;
 22535  			if ( p === UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;
 22536  			if ( p === UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;
 22537  
 22538  			if ( p === ByteType ) return _gl.BYTE;
 22539  			if ( p === ShortType ) return _gl.SHORT;
 22540  			if ( p === UnsignedShortType ) return _gl.UNSIGNED_SHORT;
 22541  			if ( p === IntType ) return _gl.INT;
 22542  			if ( p === UnsignedIntType ) return _gl.UNSIGNED_INT;
 22543  			if ( p === FloatType ) return _gl.FLOAT;
 22544  
 22545  			if ( p === HalfFloatType ) {
 22546  
 22547  				extension = extensions.get( 'OES_texture_half_float' );
 22548  
 22549  				if ( extension !== null ) return extension.HALF_FLOAT_OES;
 22550  
 22551  			}
 22552  
 22553  			if ( p === AlphaFormat ) return _gl.ALPHA;
 22554  			if ( p === RGBFormat ) return _gl.RGB;
 22555  			if ( p === RGBAFormat ) return _gl.RGBA;
 22556  			if ( p === LuminanceFormat ) return _gl.LUMINANCE;
 22557  			if ( p === LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;
 22558  			if ( p === DepthFormat ) return _gl.DEPTH_COMPONENT;
 22559  			if ( p === DepthStencilFormat ) return _gl.DEPTH_STENCIL;
 22560  
 22561  			if ( p === AddEquation ) return _gl.FUNC_ADD;
 22562  			if ( p === SubtractEquation ) return _gl.FUNC_SUBTRACT;
 22563  			if ( p === ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;
 22564  
 22565  			if ( p === ZeroFactor ) return _gl.ZERO;
 22566  			if ( p === OneFactor ) return _gl.ONE;
 22567  			if ( p === SrcColorFactor ) return _gl.SRC_COLOR;
 22568  			if ( p === OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;
 22569  			if ( p === SrcAlphaFactor ) return _gl.SRC_ALPHA;
 22570  			if ( p === OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;
 22571  			if ( p === DstAlphaFactor ) return _gl.DST_ALPHA;
 22572  			if ( p === OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;
 22573  
 22574  			if ( p === DstColorFactor ) return _gl.DST_COLOR;
 22575  			if ( p === OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
 22576  			if ( p === SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;
 22577  
 22578  			if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||
 22579  				p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
 22580  
 22581  				extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
 22582  
 22583  				if ( extension !== null ) {
 22584  
 22585  					if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
 22586  					if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
 22587  					if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
 22588  					if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
 22589  
 22590  				}
 22591  
 22592  			}
 22593  
 22594  			if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||
 22595  				p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {
 22596  
 22597  				extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
 22598  
 22599  				if ( extension !== null ) {
 22600  
 22601  					if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
 22602  					if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
 22603  					if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
 22604  					if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
 22605  
 22606  				}
 22607  
 22608  			}
 22609  
 22610  			if ( p === RGB_ETC1_Format ) {
 22611  
 22612  				extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
 22613  
 22614  				if ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL;
 22615  
 22616  			}
 22617  
 22618  			if ( p === MinEquation || p === MaxEquation ) {
 22619  
 22620  				extension = extensions.get( 'EXT_blend_minmax' );
 22621  
 22622  				if ( extension !== null ) {
 22623  
 22624  					if ( p === MinEquation ) return extension.MIN_EXT;
 22625  					if ( p === MaxEquation ) return extension.MAX_EXT;
 22626  
 22627  				}
 22628  
 22629  			}
 22630  
 22631  			if ( p === UnsignedInt248Type ) {
 22632  
 22633  				extension = extensions.get( 'WEBGL_depth_texture' );
 22634  
 22635  				if ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL;
 22636  
 22637  			}
 22638  
 22639  			return 0;
 22640  
 22641  		}
 22642  
 22643  	}
 22644  
 22645  	/**
 22646  	 * @author mrdoob / http://mrdoob.com/
 22647  	 * @author alteredq / http://alteredqualia.com/
 22648  	 */
 22649  
 22650  	function FogExp2 ( color, density ) {
 22651  
 22652  		this.name = '';
 22653  
 22654  		this.color = new Color( color );
 22655  		this.density = ( density !== undefined ) ? density : 0.00025;
 22656  
 22657  	}
 22658  
 22659  	FogExp2.prototype.isFogExp2 = true;
 22660  
 22661  	FogExp2.prototype.clone = function () {
 22662  
 22663  		return new FogExp2( this.color.getHex(), this.density );
 22664  
 22665  	};
 22666  
 22667  	FogExp2.prototype.toJSON = function ( meta ) {
 22668  
 22669  		return {
 22670  			type: 'FogExp2',
 22671  			color: this.color.getHex(),
 22672  			density: this.density
 22673  		};
 22674  
 22675  	};
 22676  
 22677  	/**
 22678  	 * @author mrdoob / http://mrdoob.com/
 22679  	 * @author alteredq / http://alteredqualia.com/
 22680  	 */
 22681  
 22682  	function Fog ( color, near, far ) {
 22683  
 22684  		this.name = '';
 22685  
 22686  		this.color = new Color( color );
 22687  
 22688  		this.near = ( near !== undefined ) ? near : 1;
 22689  		this.far = ( far !== undefined ) ? far : 1000;
 22690  
 22691  	}
 22692  
 22693  	Fog.prototype.isFog = true;
 22694  
 22695  	Fog.prototype.clone = function () {
 22696  
 22697  		return new Fog( this.color.getHex(), this.near, this.far );
 22698  
 22699  	};
 22700  
 22701  	Fog.prototype.toJSON = function ( meta ) {
 22702  
 22703  		return {
 22704  			type: 'Fog',
 22705  			color: this.color.getHex(),
 22706  			near: this.near,
 22707  			far: this.far
 22708  		};
 22709  
 22710  	};
 22711  
 22712  	/**
 22713  	 * @author mrdoob / http://mrdoob.com/
 22714  	 */
 22715  
 22716  	function Scene () {
 22717  
 22718  		Object3D.call( this );
 22719  
 22720  		this.type = 'Scene';
 22721  
 22722  		this.background = null;
 22723  		this.fog = null;
 22724  		this.overrideMaterial = null;
 22725  
 22726  		this.autoUpdate = true; // checked by the renderer
 22727  
 22728  	}
 22729  
 22730  	Scene.prototype = Object.create( Object3D.prototype );
 22731  
 22732  	Scene.prototype.constructor = Scene;
 22733  
 22734  	Scene.prototype.copy = function ( source, recursive ) {
 22735  
 22736  		Object3D.prototype.copy.call( this, source, recursive );
 22737  
 22738  		if ( source.background !== null ) this.background = source.background.clone();
 22739  		if ( source.fog !== null ) this.fog = source.fog.clone();
 22740  		if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();
 22741  
 22742  		this.autoUpdate = source.autoUpdate;
 22743  		this.matrixAutoUpdate = source.matrixAutoUpdate;
 22744  
 22745  		return this;
 22746  
 22747  	};
 22748  
 22749  	Scene.prototype.toJSON = function ( meta ) {
 22750  
 22751  		var data = Object3D.prototype.toJSON.call( this, meta );
 22752  
 22753  		if ( this.background !== null ) data.object.background = this.background.toJSON( meta );
 22754  		if ( this.fog !== null ) data.object.fog = this.fog.toJSON();
 22755  
 22756  		return data;
 22757  
 22758  	};
 22759  
 22760  	/**
 22761  	 * @author mikael emtinger / http://gomo.se/
 22762  	 * @author alteredq / http://alteredqualia.com/
 22763  	 */
 22764  
 22765  	function LensFlare( texture, size, distance, blending, color ) {
 22766  
 22767  		Object3D.call( this );
 22768  
 22769  		this.lensFlares = [];
 22770  
 22771  		this.positionScreen = new Vector3();
 22772  		this.customUpdateCallback = undefined;
 22773  
 22774  		if ( texture !== undefined ) {
 22775  
 22776  			this.add( texture, size, distance, blending, color );
 22777  
 22778  		}
 22779  
 22780  	}
 22781  
 22782  	LensFlare.prototype = Object.assign( Object.create( Object3D.prototype ), {
 22783  
 22784  		constructor: LensFlare,
 22785  
 22786  		isLensFlare: true,
 22787  
 22788  		copy: function ( source ) {
 22789  
 22790  			Object3D.prototype.copy.call( this, source );
 22791  
 22792  			this.positionScreen.copy( source.positionScreen );
 22793  			this.customUpdateCallback = source.customUpdateCallback;
 22794  
 22795  			for ( var i = 0, l = source.lensFlares.length; i < l; i ++ ) {
 22796  
 22797  				this.lensFlares.push( source.lensFlares[ i ] );
 22798  
 22799  			}
 22800  
 22801  			return this;
 22802  
 22803  		},
 22804  
 22805  		add: function ( texture, size, distance, blending, color, opacity ) {
 22806  
 22807  			if ( size === undefined ) size = - 1;
 22808  			if ( distance === undefined ) distance = 0;
 22809  			if ( opacity === undefined ) opacity = 1;
 22810  			if ( color === undefined ) color = new Color( 0xffffff );
 22811  			if ( blending === undefined ) blending = NormalBlending;
 22812  
 22813  			distance = Math.min( distance, Math.max( 0, distance ) );
 22814  
 22815  			this.lensFlares.push( {
 22816  				texture: texture,	// THREE.Texture
 22817  				size: size, 		// size in pixels (-1 = use texture.width)
 22818  				distance: distance, 	// distance (0-1) from light source (0=at light source)
 22819  				x: 0, y: 0, z: 0,	// screen position (-1 => 1) z = 0 is in front z = 1 is back
 22820  				scale: 1, 		// scale
 22821  				rotation: 0, 		// rotation
 22822  				opacity: opacity,	// opacity
 22823  				color: color,		// color
 22824  				blending: blending	// blending
 22825  			} );
 22826  
 22827  		},
 22828  
 22829  		/*
 22830  		 * Update lens flares update positions on all flares based on the screen position
 22831  		 * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way.
 22832  		 */
 22833  
 22834  		updateLensFlares: function () {
 22835  
 22836  			var f, fl = this.lensFlares.length;
 22837  			var flare;
 22838  			var vecX = - this.positionScreen.x * 2;
 22839  			var vecY = - this.positionScreen.y * 2;
 22840  
 22841  			for ( f = 0; f < fl; f ++ ) {
 22842  
 22843  				flare = this.lensFlares[ f ];
 22844  
 22845  				flare.x = this.positionScreen.x + vecX * flare.distance;
 22846  				flare.y = this.positionScreen.y + vecY * flare.distance;
 22847  
 22848  				flare.wantedRotation = flare.x * Math.PI * 0.25;
 22849  				flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25;
 22850  
 22851  			}
 22852  
 22853  		}
 22854  
 22855  	} );
 22856  
 22857  	/**
 22858  	 * @author alteredq / http://alteredqualia.com/
 22859  	 *
 22860  	 * parameters = {
 22861  	 *  color: <hex>,
 22862  	 *  opacity: <float>,
 22863  	 *  map: new THREE.Texture( <Image> ),
 22864  	 *
 22865  	 *	uvOffset: new THREE.Vector2(),
 22866  	 *	uvScale: new THREE.Vector2()
 22867  	 * }
 22868  	 */
 22869  
 22870  	function SpriteMaterial( parameters ) {
 22871  
 22872  		Material.call( this );
 22873  
 22874  		this.type = 'SpriteMaterial';
 22875  
 22876  		this.color = new Color( 0xffffff );
 22877  		this.map = null;
 22878  
 22879  		this.rotation = 0;
 22880  
 22881  		this.fog = false;
 22882  		this.lights = false;
 22883  
 22884  		this.setValues( parameters );
 22885  
 22886  	}
 22887  
 22888  	SpriteMaterial.prototype = Object.create( Material.prototype );
 22889  	SpriteMaterial.prototype.constructor = SpriteMaterial;
 22890  
 22891  	SpriteMaterial.prototype.copy = function ( source ) {
 22892  
 22893  		Material.prototype.copy.call( this, source );
 22894  
 22895  		this.color.copy( source.color );
 22896  		this.map = source.map;
 22897  
 22898  		this.rotation = source.rotation;
 22899  
 22900  		return this;
 22901  
 22902  	};
 22903  
 22904  	/**
 22905  	 * @author mikael emtinger / http://gomo.se/
 22906  	 * @author alteredq / http://alteredqualia.com/
 22907  	 */
 22908  
 22909  	function Sprite( material ) {
 22910  
 22911  		Object3D.call( this );
 22912  
 22913  		this.type = 'Sprite';
 22914  
 22915  		this.material = ( material !== undefined ) ? material : new SpriteMaterial();
 22916  
 22917  	}
 22918  
 22919  	Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), {
 22920  
 22921  		constructor: Sprite,
 22922  
 22923  		isSprite: true,
 22924  
 22925  		raycast: ( function () {
 22926  
 22927  			var matrixPosition = new Vector3();
 22928  
 22929  			return function raycast( raycaster, intersects ) {
 22930  
 22931  				matrixPosition.setFromMatrixPosition( this.matrixWorld );
 22932  
 22933  				var distanceSq = raycaster.ray.distanceSqToPoint( matrixPosition );
 22934  				var guessSizeSq = this.scale.x * this.scale.y / 4;
 22935  
 22936  				if ( distanceSq > guessSizeSq ) {
 22937  
 22938  					return;
 22939  
 22940  				}
 22941  
 22942  				intersects.push( {
 22943  
 22944  					distance: Math.sqrt( distanceSq ),
 22945  					point: this.position,
 22946  					face: null,
 22947  					object: this
 22948  
 22949  				} );
 22950  
 22951  			};
 22952  
 22953  		}() ),
 22954  
 22955  		clone: function () {
 22956  
 22957  			return new this.constructor( this.material ).copy( this );
 22958  
 22959  		}
 22960  
 22961  	} );
 22962  
 22963  	/**
 22964  	 * @author mikael emtinger / http://gomo.se/
 22965  	 * @author alteredq / http://alteredqualia.com/
 22966  	 * @author mrdoob / http://mrdoob.com/
 22967  	 */
 22968  
 22969  	function LOD() {
 22970  
 22971  		Object3D.call( this );
 22972  
 22973  		this.type = 'LOD';
 22974  
 22975  		Object.defineProperties( this, {
 22976  			levels: {
 22977  				enumerable: true,
 22978  				value: []
 22979  			}
 22980  		} );
 22981  
 22982  	}
 22983  
 22984  
 22985  	LOD.prototype = Object.assign( Object.create( Object3D.prototype ), {
 22986  
 22987  		constructor: LOD,
 22988  
 22989  		copy: function ( source ) {
 22990  
 22991  			Object3D.prototype.copy.call( this, source, false );
 22992  
 22993  			var levels = source.levels;
 22994  
 22995  			for ( var i = 0, l = levels.length; i < l; i ++ ) {
 22996  
 22997  				var level = levels[ i ];
 22998  
 22999  				this.addLevel( level.object.clone(), level.distance );
 23000  
 23001  			}
 23002  
 23003  			return this;
 23004  
 23005  		},
 23006  
 23007  		addLevel: function ( object, distance ) {
 23008  
 23009  			if ( distance === undefined ) distance = 0;
 23010  
 23011  			distance = Math.abs( distance );
 23012  
 23013  			var levels = this.levels;
 23014  
 23015  			for ( var l = 0; l < levels.length; l ++ ) {
 23016  
 23017  				if ( distance < levels[ l ].distance ) {
 23018  
 23019  					break;
 23020  
 23021  				}
 23022  
 23023  			}
 23024  
 23025  			levels.splice( l, 0, { distance: distance, object: object } );
 23026  
 23027  			this.add( object );
 23028  
 23029  		},
 23030  
 23031  		getObjectForDistance: function ( distance ) {
 23032  
 23033  			var levels = this.levels;
 23034  
 23035  			for ( var i = 1, l = levels.length; i < l; i ++ ) {
 23036  
 23037  				if ( distance < levels[ i ].distance ) {
 23038  
 23039  					break;
 23040  
 23041  				}
 23042  
 23043  			}
 23044  
 23045  			return levels[ i - 1 ].object;
 23046  
 23047  		},
 23048  
 23049  		raycast: ( function () {
 23050  
 23051  			var matrixPosition = new Vector3();
 23052  
 23053  			return function raycast( raycaster, intersects ) {
 23054  
 23055  				matrixPosition.setFromMatrixPosition( this.matrixWorld );
 23056  
 23057  				var distance = raycaster.ray.origin.distanceTo( matrixPosition );
 23058  
 23059  				this.getObjectForDistance( distance ).raycast( raycaster, intersects );
 23060  
 23061  			};
 23062  
 23063  		}() ),
 23064  
 23065  		update: function () {
 23066  
 23067  			var v1 = new Vector3();
 23068  			var v2 = new Vector3();
 23069  
 23070  			return function update( camera ) {
 23071  
 23072  				var levels = this.levels;
 23073  
 23074  				if ( levels.length > 1 ) {
 23075  
 23076  					v1.setFromMatrixPosition( camera.matrixWorld );
 23077  					v2.setFromMatrixPosition( this.matrixWorld );
 23078  
 23079  					var distance = v1.distanceTo( v2 );
 23080  
 23081  					levels[ 0 ].object.visible = true;
 23082  
 23083  					for ( var i = 1, l = levels.length; i < l; i ++ ) {
 23084  
 23085  						if ( distance >= levels[ i ].distance ) {
 23086  
 23087  							levels[ i - 1 ].object.visible = false;
 23088  							levels[ i ].object.visible = true;
 23089  
 23090  						} else {
 23091  
 23092  							break;
 23093  
 23094  						}
 23095  
 23096  					}
 23097  
 23098  					for ( ; i < l; i ++ ) {
 23099  
 23100  						levels[ i ].object.visible = false;
 23101  
 23102  					}
 23103  
 23104  				}
 23105  
 23106  			};
 23107  
 23108  		}(),
 23109  
 23110  		toJSON: function ( meta ) {
 23111  
 23112  			var data = Object3D.prototype.toJSON.call( this, meta );
 23113  
 23114  			data.object.levels = [];
 23115  
 23116  			var levels = this.levels;
 23117  
 23118  			for ( var i = 0, l = levels.length; i < l; i ++ ) {
 23119  
 23120  				var level = levels[ i ];
 23121  
 23122  				data.object.levels.push( {
 23123  					object: level.object.uuid,
 23124  					distance: level.distance
 23125  				} );
 23126  
 23127  			}
 23128  
 23129  			return data;
 23130  
 23131  		}
 23132  
 23133  	} );
 23134  
 23135  	/**
 23136  	 * @author mikael emtinger / http://gomo.se/
 23137  	 * @author alteredq / http://alteredqualia.com/
 23138  	 * @author michael guerrero / http://realitymeltdown.com
 23139  	 * @author ikerr / http://verold.com
 23140  	 */
 23141  
 23142  	function Skeleton( bones, boneInverses, useVertexTexture ) {
 23143  
 23144  		this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;
 23145  
 23146  		this.identityMatrix = new Matrix4();
 23147  
 23148  		// copy the bone array
 23149  
 23150  		bones = bones || [];
 23151  
 23152  		this.bones = bones.slice( 0 );
 23153  
 23154  		// create a bone texture or an array of floats
 23155  
 23156  		if ( this.useVertexTexture ) {
 23157  
 23158  			// layout (1 matrix = 4 pixels)
 23159  			//      RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
 23160  			//  with  8x8  pixel texture max   16 bones * 4 pixels =  (8 * 8)
 23161  			//       16x16 pixel texture max   64 bones * 4 pixels = (16 * 16)
 23162  			//       32x32 pixel texture max  256 bones * 4 pixels = (32 * 32)
 23163  			//       64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
 23164  
 23165  
 23166  			var size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix
 23167  			size = _Math.nextPowerOfTwo( Math.ceil( size ) );
 23168  			size = Math.max( size, 4 );
 23169  
 23170  			this.boneTextureWidth = size;
 23171  			this.boneTextureHeight = size;
 23172  
 23173  			this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
 23174  			this.boneTexture = new DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, RGBAFormat, FloatType );
 23175  
 23176  		} else {
 23177  
 23178  			this.boneMatrices = new Float32Array( 16 * this.bones.length );
 23179  
 23180  		}
 23181  
 23182  		// use the supplied bone inverses or calculate the inverses
 23183  
 23184  		if ( boneInverses === undefined ) {
 23185  
 23186  			this.calculateInverses();
 23187  
 23188  		} else {
 23189  
 23190  			if ( this.bones.length === boneInverses.length ) {
 23191  
 23192  				this.boneInverses = boneInverses.slice( 0 );
 23193  
 23194  			} else {
 23195  
 23196  				console.warn( 'THREE.Skeleton bonInverses is the wrong length.' );
 23197  
 23198  				this.boneInverses = [];
 23199  
 23200  				for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
 23201  
 23202  					this.boneInverses.push( new Matrix4() );
 23203  
 23204  				}
 23205  
 23206  			}
 23207  
 23208  		}
 23209  
 23210  	}
 23211  
 23212  	Object.assign( Skeleton.prototype, {
 23213  
 23214  		calculateInverses: function () {
 23215  
 23216  			this.boneInverses = [];
 23217  
 23218  			for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
 23219  
 23220  				var inverse = new Matrix4();
 23221  
 23222  				if ( this.bones[ b ] ) {
 23223  
 23224  					inverse.getInverse( this.bones[ b ].matrixWorld );
 23225  
 23226  				}
 23227  
 23228  				this.boneInverses.push( inverse );
 23229  
 23230  			}
 23231  
 23232  		},
 23233  
 23234  		pose: function () {
 23235  
 23236  			var bone;
 23237  
 23238  			// recover the bind-time world matrices
 23239  
 23240  			for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
 23241  
 23242  				bone = this.bones[ b ];
 23243  
 23244  				if ( bone ) {
 23245  
 23246  					bone.matrixWorld.getInverse( this.boneInverses[ b ] );
 23247  
 23248  				}
 23249  
 23250  			}
 23251  
 23252  			// compute the local matrices, positions, rotations and scales
 23253  
 23254  			for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
 23255  
 23256  				bone = this.bones[ b ];
 23257  
 23258  				if ( bone ) {
 23259  
 23260  					if ( bone.parent && bone.parent.isBone ) {
 23261  
 23262  						bone.matrix.getInverse( bone.parent.matrixWorld );
 23263  						bone.matrix.multiply( bone.matrixWorld );
 23264  
 23265  					} else {
 23266  
 23267  						bone.matrix.copy( bone.matrixWorld );
 23268  
 23269  					}
 23270  
 23271  					bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
 23272  
 23273  				}
 23274  
 23275  			}
 23276  
 23277  		},
 23278  
 23279  		update: ( function () {
 23280  
 23281  			var offsetMatrix = new Matrix4();
 23282  
 23283  			return function update() {
 23284  
 23285  				// flatten bone matrices to array
 23286  
 23287  				for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
 23288  
 23289  					// compute the offset between the current and the original transform
 23290  
 23291  					var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix;
 23292  
 23293  					offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] );
 23294  					offsetMatrix.toArray( this.boneMatrices, b * 16 );
 23295  
 23296  				}
 23297  
 23298  				if ( this.useVertexTexture ) {
 23299  
 23300  					this.boneTexture.needsUpdate = true;
 23301  
 23302  				}
 23303  
 23304  			};
 23305  
 23306  		} )(),
 23307  
 23308  		clone: function () {
 23309  
 23310  			return new Skeleton( this.bones, this.boneInverses, this.useVertexTexture );
 23311  
 23312  		}
 23313  
 23314  	} );
 23315  
 23316  	/**
 23317  	 * @author mikael emtinger / http://gomo.se/
 23318  	 * @author alteredq / http://alteredqualia.com/
 23319  	 * @author ikerr / http://verold.com
 23320  	 */
 23321  
 23322  	function Bone() {
 23323  
 23324  		Object3D.call( this );
 23325  
 23326  		this.type = 'Bone';
 23327  
 23328  	}
 23329  
 23330  	Bone.prototype = Object.assign( Object.create( Object3D.prototype ), {
 23331  
 23332  		constructor: Bone,
 23333  
 23334  		isBone: true
 23335  
 23336  	} );
 23337  
 23338  	/**
 23339  	 * @author mikael emtinger / http://gomo.se/
 23340  	 * @author alteredq / http://alteredqualia.com/
 23341  	 * @author ikerr / http://verold.com
 23342  	 */
 23343  
 23344  	function SkinnedMesh( geometry, material, useVertexTexture ) {
 23345  
 23346  		Mesh.call( this, geometry, material );
 23347  
 23348  		this.type = 'SkinnedMesh';
 23349  
 23350  		this.bindMode = "attached";
 23351  		this.bindMatrix = new Matrix4();
 23352  		this.bindMatrixInverse = new Matrix4();
 23353  
 23354  		// init bones
 23355  
 23356  		// TODO: remove bone creation as there is no reason (other than
 23357  		// convenience) for THREE.SkinnedMesh to do this.
 23358  
 23359  		var bones = [];
 23360  
 23361  		if ( this.geometry && this.geometry.bones !== undefined ) {
 23362  
 23363  			var bone, gbone;
 23364  
 23365  			for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) {
 23366  
 23367  				gbone = this.geometry.bones[ b ];
 23368  
 23369  				bone = new Bone();
 23370  				bones.push( bone );
 23371  
 23372  				bone.name = gbone.name;
 23373  				bone.position.fromArray( gbone.pos );
 23374  				bone.quaternion.fromArray( gbone.rotq );
 23375  				if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl );
 23376  
 23377  			}
 23378  
 23379  			for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) {
 23380  
 23381  				gbone = this.geometry.bones[ b ];
 23382  
 23383  				if ( gbone.parent !== - 1 && gbone.parent !== null &&
 23384  						bones[ gbone.parent ] !== undefined ) {
 23385  
 23386  					bones[ gbone.parent ].add( bones[ b ] );
 23387  
 23388  				} else {
 23389  
 23390  					this.add( bones[ b ] );
 23391  
 23392  				}
 23393  
 23394  			}
 23395  
 23396  		}
 23397  
 23398  		this.normalizeSkinWeights();
 23399  
 23400  		this.updateMatrixWorld( true );
 23401  		this.bind( new Skeleton( bones, undefined, useVertexTexture ), this.matrixWorld );
 23402  
 23403  	}
 23404  
 23405  
 23406  	SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 23407  
 23408  		constructor: SkinnedMesh,
 23409  
 23410  		isSkinnedMesh: true,
 23411  
 23412  		bind: function( skeleton, bindMatrix ) {
 23413  
 23414  			this.skeleton = skeleton;
 23415  
 23416  			if ( bindMatrix === undefined ) {
 23417  
 23418  				this.updateMatrixWorld( true );
 23419  
 23420  				this.skeleton.calculateInverses();
 23421  
 23422  				bindMatrix = this.matrixWorld;
 23423  
 23424  			}
 23425  
 23426  			this.bindMatrix.copy( bindMatrix );
 23427  			this.bindMatrixInverse.getInverse( bindMatrix );
 23428  
 23429  		},
 23430  
 23431  		pose: function () {
 23432  
 23433  			this.skeleton.pose();
 23434  
 23435  		},
 23436  
 23437  		normalizeSkinWeights: function () {
 23438  
 23439  			if ( this.geometry && this.geometry.isGeometry ) {
 23440  
 23441  				for ( var i = 0; i < this.geometry.skinWeights.length; i ++ ) {
 23442  
 23443  					var sw = this.geometry.skinWeights[ i ];
 23444  
 23445  					var scale = 1.0 / sw.lengthManhattan();
 23446  
 23447  					if ( scale !== Infinity ) {
 23448  
 23449  						sw.multiplyScalar( scale );
 23450  
 23451  					} else {
 23452  
 23453  						sw.set( 1, 0, 0, 0 ); // do something reasonable
 23454  
 23455  					}
 23456  
 23457  				}
 23458  
 23459  			} else if ( this.geometry && this.geometry.isBufferGeometry ) {
 23460  
 23461  				var vec = new Vector4();
 23462  
 23463  				var skinWeight = this.geometry.attributes.skinWeight;
 23464  
 23465  				for ( var i = 0; i < skinWeight.count; i ++ ) {
 23466  
 23467  					vec.x = skinWeight.getX( i );
 23468  					vec.y = skinWeight.getY( i );
 23469  					vec.z = skinWeight.getZ( i );
 23470  					vec.w = skinWeight.getW( i );
 23471  
 23472  					var scale = 1.0 / vec.lengthManhattan();
 23473  
 23474  					if ( scale !== Infinity ) {
 23475  
 23476  						vec.multiplyScalar( scale );
 23477  
 23478  					} else {
 23479  
 23480  						vec.set( 1, 0, 0, 0 ); // do something reasonable
 23481  
 23482  					}
 23483  
 23484  					skinWeight.setXYZW( i, vec.x, vec.y, vec.z, vec.w );
 23485  
 23486  				}
 23487  
 23488  			}
 23489  
 23490  		},
 23491  
 23492  		updateMatrixWorld: function( force ) {
 23493  
 23494  			Mesh.prototype.updateMatrixWorld.call( this, true );
 23495  
 23496  			if ( this.bindMode === "attached" ) {
 23497  
 23498  				this.bindMatrixInverse.getInverse( this.matrixWorld );
 23499  
 23500  			} else if ( this.bindMode === "detached" ) {
 23501  
 23502  				this.bindMatrixInverse.getInverse( this.bindMatrix );
 23503  
 23504  			} else {
 23505  
 23506  				console.warn( 'THREE.SkinnedMesh unrecognized bindMode: ' + this.bindMode );
 23507  
 23508  			}
 23509  
 23510  		},
 23511  
 23512  		clone: function() {
 23513  
 23514  			return new this.constructor( this.geometry, this.material, this.skeleton.useVertexTexture ).copy( this );
 23515  
 23516  		}
 23517  
 23518  	} );
 23519  
 23520  	/**
 23521  	 * @author mrdoob / http://mrdoob.com/
 23522  	 * @author alteredq / http://alteredqualia.com/
 23523  	 *
 23524  	 * parameters = {
 23525  	 *  color: <hex>,
 23526  	 *  opacity: <float>,
 23527  	 *
 23528  	 *  linewidth: <float>,
 23529  	 *  linecap: "round",
 23530  	 *  linejoin: "round"
 23531  	 * }
 23532  	 */
 23533  
 23534  	function LineBasicMaterial( parameters ) {
 23535  
 23536  		Material.call( this );
 23537  
 23538  		this.type = 'LineBasicMaterial';
 23539  
 23540  		this.color = new Color( 0xffffff );
 23541  
 23542  		this.linewidth = 1;
 23543  		this.linecap = 'round';
 23544  		this.linejoin = 'round';
 23545  
 23546  		this.lights = false;
 23547  
 23548  		this.setValues( parameters );
 23549  
 23550  	}
 23551  
 23552  	LineBasicMaterial.prototype = Object.create( Material.prototype );
 23553  	LineBasicMaterial.prototype.constructor = LineBasicMaterial;
 23554  
 23555  	LineBasicMaterial.prototype.isLineBasicMaterial = true;
 23556  
 23557  	LineBasicMaterial.prototype.copy = function ( source ) {
 23558  
 23559  		Material.prototype.copy.call( this, source );
 23560  
 23561  		this.color.copy( source.color );
 23562  
 23563  		this.linewidth = source.linewidth;
 23564  		this.linecap = source.linecap;
 23565  		this.linejoin = source.linejoin;
 23566  
 23567  		return this;
 23568  
 23569  	};
 23570  
 23571  	/**
 23572  	 * @author mrdoob / http://mrdoob.com/
 23573  	 */
 23574  
 23575  	function Line( geometry, material, mode ) {
 23576  
 23577  		if ( mode === 1 ) {
 23578  
 23579  			console.warn( 'THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.' );
 23580  			return new LineSegments( geometry, material );
 23581  
 23582  		}
 23583  
 23584  		Object3D.call( this );
 23585  
 23586  		this.type = 'Line';
 23587  
 23588  		this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
 23589  		this.material = material !== undefined ? material : new LineBasicMaterial( { color: Math.random() * 0xffffff } );
 23590  
 23591  	}
 23592  
 23593  	Line.prototype = Object.assign( Object.create( Object3D.prototype ), {
 23594  
 23595  		constructor: Line,
 23596  
 23597  		isLine: true,
 23598  
 23599  		raycast: ( function () {
 23600  
 23601  			var inverseMatrix = new Matrix4();
 23602  			var ray = new Ray();
 23603  			var sphere = new Sphere();
 23604  
 23605  			return function raycast( raycaster, intersects ) {
 23606  
 23607  				var precision = raycaster.linePrecision;
 23608  				var precisionSq = precision * precision;
 23609  
 23610  				var geometry = this.geometry;
 23611  				var matrixWorld = this.matrixWorld;
 23612  
 23613  				// Checking boundingSphere distance to ray
 23614  
 23615  				if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
 23616  
 23617  				sphere.copy( geometry.boundingSphere );
 23618  				sphere.applyMatrix4( matrixWorld );
 23619  
 23620  				if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
 23621  
 23622  				//
 23623  
 23624  				inverseMatrix.getInverse( matrixWorld );
 23625  				ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
 23626  
 23627  				var vStart = new Vector3();
 23628  				var vEnd = new Vector3();
 23629  				var interSegment = new Vector3();
 23630  				var interRay = new Vector3();
 23631  				var step = (this && this.isLineSegments) ? 2 : 1;
 23632  
 23633  				if ( geometry.isBufferGeometry ) {
 23634  
 23635  					var index = geometry.index;
 23636  					var attributes = geometry.attributes;
 23637  					var positions = attributes.position.array;
 23638  
 23639  					if ( index !== null ) {
 23640  
 23641  						var indices = index.array;
 23642  
 23643  						for ( var i = 0, l = indices.length - 1; i < l; i += step ) {
 23644  
 23645  							var a = indices[ i ];
 23646  							var b = indices[ i + 1 ];
 23647  
 23648  							vStart.fromArray( positions, a * 3 );
 23649  							vEnd.fromArray( positions, b * 3 );
 23650  
 23651  							var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
 23652  
 23653  							if ( distSq > precisionSq ) continue;
 23654  
 23655  							interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
 23656  
 23657  							var distance = raycaster.ray.origin.distanceTo( interRay );
 23658  
 23659  							if ( distance < raycaster.near || distance > raycaster.far ) continue;
 23660  
 23661  							intersects.push( {
 23662  
 23663  								distance: distance,
 23664  								// What do we want? intersection point on the ray or on the segment??
 23665  								// point: raycaster.ray.at( distance ),
 23666  								point: interSegment.clone().applyMatrix4( this.matrixWorld ),
 23667  								index: i,
 23668  								face: null,
 23669  								faceIndex: null,
 23670  								object: this
 23671  
 23672  							} );
 23673  
 23674  						}
 23675  
 23676  					} else {
 23677  
 23678  						for ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) {
 23679  
 23680  							vStart.fromArray( positions, 3 * i );
 23681  							vEnd.fromArray( positions, 3 * i + 3 );
 23682  
 23683  							var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
 23684  
 23685  							if ( distSq > precisionSq ) continue;
 23686  
 23687  							interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
 23688  
 23689  							var distance = raycaster.ray.origin.distanceTo( interRay );
 23690  
 23691  							if ( distance < raycaster.near || distance > raycaster.far ) continue;
 23692  
 23693  							intersects.push( {
 23694  
 23695  								distance: distance,
 23696  								// What do we want? intersection point on the ray or on the segment??
 23697  								// point: raycaster.ray.at( distance ),
 23698  								point: interSegment.clone().applyMatrix4( this.matrixWorld ),
 23699  								index: i,
 23700  								face: null,
 23701  								faceIndex: null,
 23702  								object: this
 23703  
 23704  							} );
 23705  
 23706  						}
 23707  
 23708  					}
 23709  
 23710  				} else if ( geometry.isGeometry ) {
 23711  
 23712  					var vertices = geometry.vertices;
 23713  					var nbVertices = vertices.length;
 23714  
 23715  					for ( var i = 0; i < nbVertices - 1; i += step ) {
 23716  
 23717  						var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment );
 23718  
 23719  						if ( distSq > precisionSq ) continue;
 23720  
 23721  						interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
 23722  
 23723  						var distance = raycaster.ray.origin.distanceTo( interRay );
 23724  
 23725  						if ( distance < raycaster.near || distance > raycaster.far ) continue;
 23726  
 23727  						intersects.push( {
 23728  
 23729  							distance: distance,
 23730  							// What do we want? intersection point on the ray or on the segment??
 23731  							// point: raycaster.ray.at( distance ),
 23732  							point: interSegment.clone().applyMatrix4( this.matrixWorld ),
 23733  							index: i,
 23734  							face: null,
 23735  							faceIndex: null,
 23736  							object: this
 23737  
 23738  						} );
 23739  
 23740  					}
 23741  
 23742  				}
 23743  
 23744  			};
 23745  
 23746  		}() ),
 23747  
 23748  		clone: function () {
 23749  
 23750  			return new this.constructor( this.geometry, this.material ).copy( this );
 23751  
 23752  		}
 23753  
 23754  	} );
 23755  
 23756  	/**
 23757  	 * @author mrdoob / http://mrdoob.com/
 23758  	 */
 23759  
 23760  	function LineSegments( geometry, material ) {
 23761  
 23762  		Line.call( this, geometry, material );
 23763  
 23764  		this.type = 'LineSegments';
 23765  
 23766  	}
 23767  
 23768  	LineSegments.prototype = Object.assign( Object.create( Line.prototype ), {
 23769  
 23770  		constructor: LineSegments,
 23771  
 23772  		isLineSegments: true
 23773  
 23774  	} );
 23775  
 23776  	/**
 23777  	 * @author mrdoob / http://mrdoob.com/
 23778  	 * @author alteredq / http://alteredqualia.com/
 23779  	 *
 23780  	 * parameters = {
 23781  	 *  color: <hex>,
 23782  	 *  opacity: <float>,
 23783  	 *  map: new THREE.Texture( <Image> ),
 23784  	 *
 23785  	 *  size: <float>,
 23786  	 *  sizeAttenuation: <bool>
 23787  	 * }
 23788  	 */
 23789  
 23790  	function PointsMaterial( parameters ) {
 23791  
 23792  		Material.call( this );
 23793  
 23794  		this.type = 'PointsMaterial';
 23795  
 23796  		this.color = new Color( 0xffffff );
 23797  
 23798  		this.map = null;
 23799  
 23800  		this.size = 1;
 23801  		this.sizeAttenuation = true;
 23802  
 23803  		this.lights = false;
 23804  
 23805  		this.setValues( parameters );
 23806  
 23807  	}
 23808  
 23809  	PointsMaterial.prototype = Object.create( Material.prototype );
 23810  	PointsMaterial.prototype.constructor = PointsMaterial;
 23811  
 23812  	PointsMaterial.prototype.isPointsMaterial = true;
 23813  
 23814  	PointsMaterial.prototype.copy = function ( source ) {
 23815  
 23816  		Material.prototype.copy.call( this, source );
 23817  
 23818  		this.color.copy( source.color );
 23819  
 23820  		this.map = source.map;
 23821  
 23822  		this.size = source.size;
 23823  		this.sizeAttenuation = source.sizeAttenuation;
 23824  
 23825  		return this;
 23826  
 23827  	};
 23828  
 23829  	/**
 23830  	 * @author alteredq / http://alteredqualia.com/
 23831  	 */
 23832  
 23833  	function Points( geometry, material ) {
 23834  
 23835  		Object3D.call( this );
 23836  
 23837  		this.type = 'Points';
 23838  
 23839  		this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
 23840  		this.material = material !== undefined ? material : new PointsMaterial( { color: Math.random() * 0xffffff } );
 23841  
 23842  	}
 23843  
 23844  	Points.prototype = Object.assign( Object.create( Object3D.prototype ), {
 23845  
 23846  		constructor: Points,
 23847  
 23848  		isPoints: true,
 23849  
 23850  		raycast: ( function () {
 23851  
 23852  			var inverseMatrix = new Matrix4();
 23853  			var ray = new Ray();
 23854  			var sphere = new Sphere();
 23855  
 23856  			return function raycast( raycaster, intersects ) {
 23857  
 23858  				var object = this;
 23859  				var geometry = this.geometry;
 23860  				var matrixWorld = this.matrixWorld;
 23861  				var threshold = raycaster.params.Points.threshold;
 23862  
 23863  				// Checking boundingSphere distance to ray
 23864  
 23865  				if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
 23866  
 23867  				sphere.copy( geometry.boundingSphere );
 23868  				sphere.applyMatrix4( matrixWorld );
 23869  
 23870  				if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
 23871  
 23872  				//
 23873  
 23874  				inverseMatrix.getInverse( matrixWorld );
 23875  				ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
 23876  
 23877  				var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
 23878  				var localThresholdSq = localThreshold * localThreshold;
 23879  				var position = new Vector3();
 23880  
 23881  				function testPoint( point, index ) {
 23882  
 23883  					var rayPointDistanceSq = ray.distanceSqToPoint( point );
 23884  
 23885  					if ( rayPointDistanceSq < localThresholdSq ) {
 23886  
 23887  						var intersectPoint = ray.closestPointToPoint( point );
 23888  						intersectPoint.applyMatrix4( matrixWorld );
 23889  
 23890  						var distance = raycaster.ray.origin.distanceTo( intersectPoint );
 23891  
 23892  						if ( distance < raycaster.near || distance > raycaster.far ) return;
 23893  
 23894  						intersects.push( {
 23895  
 23896  							distance: distance,
 23897  							distanceToRay: Math.sqrt( rayPointDistanceSq ),
 23898  							point: intersectPoint.clone(),
 23899  							index: index,
 23900  							face: null,
 23901  							object: object
 23902  
 23903  						} );
 23904  
 23905  					}
 23906  
 23907  				}
 23908  
 23909  				if ( geometry.isBufferGeometry ) {
 23910  
 23911  					var index = geometry.index;
 23912  					var attributes = geometry.attributes;
 23913  					var positions = attributes.position.array;
 23914  
 23915  					if ( index !== null ) {
 23916  
 23917  						var indices = index.array;
 23918  
 23919  						for ( var i = 0, il = indices.length; i < il; i ++ ) {
 23920  
 23921  							var a = indices[ i ];
 23922  
 23923  							position.fromArray( positions, a * 3 );
 23924  
 23925  							testPoint( position, a );
 23926  
 23927  						}
 23928  
 23929  					} else {
 23930  
 23931  						for ( var i = 0, l = positions.length / 3; i < l; i ++ ) {
 23932  
 23933  							position.fromArray( positions, i * 3 );
 23934  
 23935  							testPoint( position, i );
 23936  
 23937  						}
 23938  
 23939  					}
 23940  
 23941  				} else {
 23942  
 23943  					var vertices = geometry.vertices;
 23944  
 23945  					for ( var i = 0, l = vertices.length; i < l; i ++ ) {
 23946  
 23947  						testPoint( vertices[ i ], i );
 23948  
 23949  					}
 23950  
 23951  				}
 23952  
 23953  			};
 23954  
 23955  		}() ),
 23956  
 23957  		clone: function () {
 23958  
 23959  			return new this.constructor( this.geometry, this.material ).copy( this );
 23960  
 23961  		}
 23962  
 23963  	} );
 23964  
 23965  	/**
 23966  	 * @author mrdoob / http://mrdoob.com/
 23967  	 */
 23968  
 23969  	function Group() {
 23970  
 23971  		Object3D.call( this );
 23972  
 23973  		this.type = 'Group';
 23974  
 23975  	}
 23976  
 23977  	Group.prototype = Object.assign( Object.create( Object3D.prototype ), {
 23978  
 23979  		constructor: Group
 23980  
 23981  	} );
 23982  
 23983  	/**
 23984  	 * @author mrdoob / http://mrdoob.com/
 23985  	 */
 23986  
 23987  	function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
 23988  
 23989  		Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
 23990  
 23991  		this.generateMipmaps = false;
 23992  
 23993  		var scope = this;
 23994  
 23995  		function update() {
 23996  
 23997  			requestAnimationFrame( update );
 23998  
 23999  			if ( video.readyState >= video.HAVE_CURRENT_DATA ) {
 24000  
 24001  				scope.needsUpdate = true;
 24002  
 24003  			}
 24004  
 24005  		}
 24006  
 24007  		update();
 24008  
 24009  	}
 24010  
 24011  	VideoTexture.prototype = Object.create( Texture.prototype );
 24012  	VideoTexture.prototype.constructor = VideoTexture;
 24013  
 24014  	/**
 24015  	 * @author alteredq / http://alteredqualia.com/
 24016  	 */
 24017  
 24018  	function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
 24019  
 24020  		Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
 24021  
 24022  		this.image = { width: width, height: height };
 24023  		this.mipmaps = mipmaps;
 24024  
 24025  		// no flipping for cube textures
 24026  		// (also flipping doesn't work for compressed textures )
 24027  
 24028  		this.flipY = false;
 24029  
 24030  		// can't generate mipmaps for compressed textures
 24031  		// mips must be embedded in DDS files
 24032  
 24033  		this.generateMipmaps = false;
 24034  
 24035  	}
 24036  
 24037  	CompressedTexture.prototype = Object.create( Texture.prototype );
 24038  	CompressedTexture.prototype.constructor = CompressedTexture;
 24039  
 24040  	CompressedTexture.prototype.isCompressedTexture = true;
 24041  
 24042  	/**
 24043  	 * @author mrdoob / http://mrdoob.com/
 24044  	 */
 24045  
 24046  	function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
 24047  
 24048  		Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
 24049  
 24050  		this.needsUpdate = true;
 24051  
 24052  	}
 24053  
 24054  	CanvasTexture.prototype = Object.create( Texture.prototype );
 24055  	CanvasTexture.prototype.constructor = CanvasTexture;
 24056  
 24057  	/**
 24058  	 * @author Matt DesLauriers / @mattdesl
 24059  	 * @author atix / arthursilber.de
 24060  	 */
 24061  
 24062  	function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) {
 24063  
 24064  		format = format !== undefined ? format : DepthFormat;
 24065  
 24066  		if ( format !== DepthFormat && format !== DepthStencilFormat ) {
 24067  
 24068  			throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' )
 24069  
 24070  		}
 24071  
 24072  		if ( type === undefined && format === DepthFormat ) type = UnsignedShortType;
 24073  		if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;
 24074  
 24075  		Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
 24076  
 24077  		this.image = { width: width, height: height };
 24078  
 24079  		this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
 24080  		this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
 24081  
 24082  		this.flipY = false;
 24083  		this.generateMipmaps	= false;
 24084  
 24085  	}
 24086  
 24087  	DepthTexture.prototype = Object.create( Texture.prototype );
 24088  	DepthTexture.prototype.constructor = DepthTexture;
 24089  	DepthTexture.prototype.isDepthTexture = true;
 24090  
 24091  	/**
 24092  	 * @author mrdoob / http://mrdoob.com/
 24093  	 * @author Mugen87 / https://github.com/Mugen87
 24094  	 */
 24095  
 24096  	function WireframeGeometry( geometry ) {
 24097  
 24098  		BufferGeometry.call( this );
 24099  
 24100  		this.type = 'WireframeGeometry';
 24101  
 24102  		// buffer
 24103  
 24104  		var vertices = [];
 24105  
 24106  		// helper variables
 24107  
 24108  		var i, j, l, o, ol;
 24109  		var edge = [ 0, 0 ], edges = {}, e;
 24110  		var key, keys = [ 'a', 'b', 'c' ];
 24111  		var vertex;
 24112  
 24113  		// different logic for Geometry and BufferGeometry
 24114  
 24115  		if ( geometry && geometry.isGeometry ) {
 24116  
 24117  			// create a data structure that contains all edges without duplicates
 24118  
 24119  			var faces = geometry.faces;
 24120  
 24121  			for ( i = 0, l = faces.length; i < l; i ++ ) {
 24122  
 24123  				var face = faces[ i ];
 24124  
 24125  				for ( j = 0; j < 3; j ++ ) {
 24126  
 24127  					edge[ 0 ] = face[ keys[ j ] ];
 24128  					edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ];
 24129  					edge.sort( sortFunction ); // sorting prevents duplicates
 24130  
 24131  					key = edge.toString();
 24132  
 24133  					if ( edges[ key ] === undefined ) {
 24134  
 24135  						edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
 24136  
 24137  					}
 24138  
 24139  				}
 24140  
 24141  			}
 24142  
 24143  			// generate vertices
 24144  
 24145  			for ( key in edges ) {
 24146  
 24147  				e = edges[ key ];
 24148  
 24149  				vertex = geometry.vertices[ e.index1 ];
 24150  				vertices.push( vertex.x, vertex.y, vertex.z );
 24151  
 24152  				vertex = geometry.vertices[ e.index2 ];
 24153  				vertices.push( vertex.x, vertex.y, vertex.z );
 24154  
 24155  			}
 24156  
 24157  		} else if ( geometry && geometry.isBufferGeometry ) {
 24158  
 24159  			var position, indices, groups;
 24160  			var group, start, count;
 24161  			var index1, index2;
 24162  
 24163  			vertex = new Vector3();
 24164  
 24165  			if ( geometry.index !== null ) {
 24166  
 24167  				// indexed BufferGeometry
 24168  
 24169  				position = geometry.attributes.position;
 24170  				indices = geometry.index;
 24171  				groups = geometry.groups;
 24172  
 24173  				if ( groups.length === 0 ) {
 24174  
 24175  					geometry.addGroup( 0, indices.count );
 24176  
 24177  				}
 24178  
 24179  				// create a data structure that contains all eges without duplicates
 24180  
 24181  				for ( o = 0, ol = groups.length; o < ol; ++ o ) {
 24182  
 24183  					group = groups[ o ];
 24184  
 24185  					start = group.start;
 24186  					count = group.count;
 24187  
 24188  					for ( i = start, l = ( start + count ); i < l; i += 3 ) {
 24189  
 24190  						for ( j = 0; j < 3; j ++ ) {
 24191  
 24192  							edge[ 0 ] = indices.getX( i + j );
 24193  							edge[ 1 ] = indices.getX( i + ( j + 1 ) % 3 );
 24194  							edge.sort( sortFunction ); // sorting prevents duplicates
 24195  
 24196  							key = edge.toString();
 24197  
 24198  							if ( edges[ key ] === undefined ) {
 24199  
 24200  								edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
 24201  
 24202  							}
 24203  
 24204  						}
 24205  
 24206  					}
 24207  
 24208  				}
 24209  
 24210  				// generate vertices
 24211  
 24212  				for ( key in edges ) {
 24213  
 24214  					e = edges[ key ];
 24215  
 24216  					vertex.fromBufferAttribute( position, e.index1 );
 24217  					vertices.push( vertex.x, vertex.y, vertex.z );
 24218  
 24219  					vertex.fromBufferAttribute( position, e.index2 );
 24220  					vertices.push( vertex.x, vertex.y, vertex.z );
 24221  
 24222  				}
 24223  
 24224  			} else {
 24225  
 24226  				// non-indexed BufferGeometry
 24227  
 24228  				position = geometry.attributes.position;
 24229  
 24230  				for ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
 24231  
 24232  					for ( j = 0; j < 3; j ++ ) {
 24233  
 24234  						// three edges per triangle, an edge is represented as (index1, index2)
 24235  						// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
 24236  
 24237  						index1 = 3 * i + j;
 24238  						vertex.fromBufferAttribute( position, index1 );
 24239  						vertices.push( vertex.x, vertex.y, vertex.z );
 24240  
 24241  						index2 = 3 * i + ( ( j + 1 ) % 3 );
 24242  						vertex.fromBufferAttribute( position, index2 );
 24243  						vertices.push( vertex.x, vertex.y, vertex.z );
 24244  
 24245  					}
 24246  
 24247  				}
 24248  
 24249  			}
 24250  
 24251  		}
 24252  
 24253  		// build geometry
 24254  
 24255  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 24256  
 24257  		// custom array sort function
 24258  
 24259  		function sortFunction( a, b ) {
 24260  
 24261  			return a - b;
 24262  
 24263  		}
 24264  
 24265  	}
 24266  
 24267  	WireframeGeometry.prototype = Object.create( BufferGeometry.prototype );
 24268  	WireframeGeometry.prototype.constructor = WireframeGeometry;
 24269  
 24270  	/**
 24271  	 * @author zz85 / https://github.com/zz85
 24272  	 *
 24273  	 * Parametric Surfaces Geometry
 24274  	 * based on the brilliant article by @prideout http://prideout.net/blog/?p=44
 24275  	 */
 24276  
 24277  	function ParametricGeometry( func, slices, stacks ) {
 24278  
 24279  		Geometry.call( this );
 24280  
 24281  		this.type = 'ParametricGeometry';
 24282  
 24283  		this.parameters = {
 24284  			func: func,
 24285  			slices: slices,
 24286  			stacks: stacks
 24287  		};
 24288  
 24289  		this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) );
 24290  		this.mergeVertices();
 24291  
 24292  	}
 24293  
 24294  	ParametricGeometry.prototype = Object.create( Geometry.prototype );
 24295  	ParametricGeometry.prototype.constructor = ParametricGeometry;
 24296  
 24297  	/**
 24298  	 * @author Mugen87 / https://github.com/Mugen87
 24299  	 *
 24300  	 * Parametric Surfaces Geometry
 24301  	 * based on the brilliant article by @prideout http://prideout.net/blog/?p=44
 24302  	 */
 24303  
 24304  	function ParametricBufferGeometry( func, slices, stacks ) {
 24305  
 24306  		BufferGeometry.call( this );
 24307  
 24308  		this.type = 'ParametricBufferGeometry';
 24309  
 24310  		this.parameters = {
 24311  			func: func,
 24312  			slices: slices,
 24313  			stacks: stacks
 24314  		};
 24315  
 24316  		// buffers
 24317  
 24318  		var indices = [];
 24319  		var vertices = [];
 24320  		var uvs = [];
 24321  
 24322  		var i, j;
 24323  
 24324  		// generate vertices and uvs
 24325  
 24326  		var sliceCount = slices + 1;
 24327  
 24328  		for ( i = 0; i <= stacks; i ++ ) {
 24329  
 24330  			var v = i / stacks;
 24331  
 24332  			for ( j = 0; j <= slices; j ++ ) {
 24333  
 24334  				var u = j / slices;
 24335  
 24336  				var p = func( u, v );
 24337  				vertices.push( p.x, p.y, p.z );
 24338  
 24339  				uvs.push( u, v );
 24340  
 24341  			}
 24342  
 24343  		}
 24344  
 24345  		// generate indices
 24346  
 24347  		for ( i = 0; i < stacks; i ++ ) {
 24348  
 24349  			for ( j = 0; j < slices; j ++ ) {
 24350  
 24351  				var a = i * sliceCount + j;
 24352  				var b = i * sliceCount + j + 1;
 24353  				var c = ( i + 1 ) * sliceCount + j + 1;
 24354  				var d = ( i + 1 ) * sliceCount + j;
 24355  
 24356  				// faces one and two
 24357  
 24358  				indices.push( a, b, d );
 24359  				indices.push( b, c, d );
 24360  
 24361  			}
 24362  
 24363  		}
 24364  
 24365  		// build geometry
 24366  
 24367  		this.setIndex( indices );
 24368  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 24369  		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 24370  
 24371  		// generate normals
 24372  
 24373  		this.computeVertexNormals();
 24374  
 24375  	}
 24376  
 24377  	ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 24378  	ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry;
 24379  
 24380  	/**
 24381  	 * @author clockworkgeek / https://github.com/clockworkgeek
 24382  	 * @author timothypratley / https://github.com/timothypratley
 24383  	 * @author WestLangley / http://github.com/WestLangley
 24384  	*/
 24385  
 24386  	function PolyhedronGeometry( vertices, indices, radius, detail ) {
 24387  
 24388  		Geometry.call( this );
 24389  
 24390  		this.type = 'PolyhedronGeometry';
 24391  
 24392  		this.parameters = {
 24393  			vertices: vertices,
 24394  			indices: indices,
 24395  			radius: radius,
 24396  			detail: detail
 24397  		};
 24398  
 24399  		this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );
 24400  		this.mergeVertices();
 24401  
 24402  	}
 24403  
 24404  	PolyhedronGeometry.prototype = Object.create( Geometry.prototype );
 24405  	PolyhedronGeometry.prototype.constructor = PolyhedronGeometry;
 24406  
 24407  	/**
 24408  	 * @author Mugen87 / https://github.com/Mugen87
 24409  	 */
 24410  
 24411  	function PolyhedronBufferGeometry( vertices, indices, radius, detail ) {
 24412  
 24413  		BufferGeometry.call( this );
 24414  
 24415  		this.type = 'PolyhedronBufferGeometry';
 24416  
 24417  		this.parameters = {
 24418  			vertices: vertices,
 24419  			indices: indices,
 24420  			radius: radius,
 24421  			detail: detail
 24422  		};
 24423  
 24424  		radius = radius || 1;
 24425  		detail = detail || 0;
 24426  
 24427  		// default buffer data
 24428  
 24429  		var vertexBuffer = [];
 24430  		var uvBuffer = [];
 24431  
 24432  		// the subdivision creates the vertex buffer data
 24433  
 24434  		subdivide( detail );
 24435  
 24436  		// all vertices should lie on a conceptual sphere with a given radius
 24437  
 24438  		appplyRadius( radius );
 24439  
 24440  		// finally, create the uv data
 24441  
 24442  		generateUVs();
 24443  
 24444  		// build non-indexed geometry
 24445  
 24446  		this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
 24447  		this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
 24448  		this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
 24449  		this.normalizeNormals();
 24450  
 24451  		// helper functions
 24452  
 24453  		function subdivide( detail ) {
 24454  
 24455  			var a = new Vector3();
 24456  			var b = new Vector3();
 24457  			var c = new Vector3();
 24458  
 24459  			// iterate over all faces and apply a subdivison with the given detail value
 24460  
 24461  			for ( var i = 0; i < indices.length; i += 3 ) {
 24462  
 24463  				// get the vertices of the face
 24464  
 24465  				getVertexByIndex( indices[ i + 0 ], a );
 24466  				getVertexByIndex( indices[ i + 1 ], b );
 24467  				getVertexByIndex( indices[ i + 2 ], c );
 24468  
 24469  				// perform subdivision
 24470  
 24471  				subdivideFace( a, b, c, detail );
 24472  
 24473  			}
 24474  
 24475  		}
 24476  
 24477  		function subdivideFace( a, b, c, detail ) {
 24478  
 24479  			var cols = Math.pow( 2, detail );
 24480  
 24481  			// we use this multidimensional array as a data structure for creating the subdivision
 24482  
 24483  			var v = [];
 24484  
 24485  			var i, j;
 24486  
 24487  			// construct all of the vertices for this subdivision
 24488  
 24489  			for ( i = 0; i <= cols; i ++ ) {
 24490  
 24491  				v[ i ] = [];
 24492  
 24493  				var aj = a.clone().lerp( c, i / cols );
 24494  				var bj = b.clone().lerp( c, i / cols );
 24495  
 24496  				var rows = cols - i;
 24497  
 24498  				for ( j = 0; j <= rows; j ++ ) {
 24499  
 24500  					if ( j === 0 && i === cols ) {
 24501  
 24502  						v[ i ][ j ] = aj;
 24503  
 24504  					} else {
 24505  
 24506  						v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
 24507  
 24508  					}
 24509  
 24510  				}
 24511  
 24512  			}
 24513  
 24514  			// construct all of the faces
 24515  
 24516  			for ( i = 0; i < cols; i ++ ) {
 24517  
 24518  				for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
 24519  
 24520  					var k = Math.floor( j / 2 );
 24521  
 24522  					if ( j % 2 === 0 ) {
 24523  
 24524  						pushVertex( v[ i ][ k + 1 ] );
 24525  						pushVertex( v[ i + 1 ][ k ] );
 24526  						pushVertex( v[ i ][ k ] );
 24527  
 24528  					} else {
 24529  
 24530  						pushVertex( v[ i ][ k + 1 ] );
 24531  						pushVertex( v[ i + 1 ][ k + 1 ] );
 24532  						pushVertex( v[ i + 1 ][ k ] );
 24533  
 24534  					}
 24535  
 24536  				}
 24537  
 24538  			}
 24539  
 24540  		}
 24541  
 24542  		function appplyRadius( radius ) {
 24543  
 24544  			var vertex = new Vector3();
 24545  
 24546  			// iterate over the entire buffer and apply the radius to each vertex
 24547  
 24548  			for ( var i = 0; i < vertexBuffer.length; i += 3 ) {
 24549  
 24550  				vertex.x = vertexBuffer[ i + 0 ];
 24551  				vertex.y = vertexBuffer[ i + 1 ];
 24552  				vertex.z = vertexBuffer[ i + 2 ];
 24553  
 24554  				vertex.normalize().multiplyScalar( radius );
 24555  
 24556  				vertexBuffer[ i + 0 ] = vertex.x;
 24557  				vertexBuffer[ i + 1 ] = vertex.y;
 24558  				vertexBuffer[ i + 2 ] = vertex.z;
 24559  
 24560  			}
 24561  
 24562  		}
 24563  
 24564  		function generateUVs() {
 24565  
 24566  			var vertex = new Vector3();
 24567  
 24568  			for ( var i = 0; i < vertexBuffer.length; i += 3 ) {
 24569  
 24570  				vertex.x = vertexBuffer[ i + 0 ];
 24571  				vertex.y = vertexBuffer[ i + 1 ];
 24572  				vertex.z = vertexBuffer[ i + 2 ];
 24573  
 24574  				var u = azimuth( vertex ) / 2 / Math.PI + 0.5;
 24575  				var v = inclination( vertex ) / Math.PI + 0.5;
 24576  				uvBuffer.push( u, 1 - v );
 24577  
 24578  			}
 24579  
 24580  			correctUVs();
 24581  
 24582  			correctSeam();
 24583  
 24584  		}
 24585  
 24586  		function correctSeam() {
 24587  
 24588  			// handle case when face straddles the seam, see #3269
 24589  
 24590  			for ( var i = 0; i < uvBuffer.length; i += 6 ) {
 24591  
 24592  				// uv data of a single face
 24593  
 24594  				var x0 = uvBuffer[ i + 0 ];
 24595  				var x1 = uvBuffer[ i + 2 ];
 24596  				var x2 = uvBuffer[ i + 4 ];
 24597  
 24598  				var max = Math.max( x0, x1, x2 );
 24599  				var min = Math.min( x0, x1, x2 );
 24600  
 24601  				// 0.9 is somewhat arbitrary
 24602  
 24603  				if ( max > 0.9 && min < 0.1 ) {
 24604  
 24605  					if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
 24606  					if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
 24607  					if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
 24608  
 24609  				}
 24610  
 24611  			}
 24612  
 24613  		}
 24614  
 24615  		function pushVertex( vertex ) {
 24616  
 24617  			vertexBuffer.push( vertex.x, vertex.y, vertex.z );
 24618  
 24619  		}
 24620  
 24621  		function getVertexByIndex( index, vertex ) {
 24622  
 24623  			var stride = index * 3;
 24624  
 24625  			vertex.x = vertices[ stride + 0 ];
 24626  			vertex.y = vertices[ stride + 1 ];
 24627  			vertex.z = vertices[ stride + 2 ];
 24628  
 24629  		}
 24630  
 24631  		function correctUVs() {
 24632  
 24633  			var a = new Vector3();
 24634  			var b = new Vector3();
 24635  			var c = new Vector3();
 24636  
 24637  			var centroid = new Vector3();
 24638  
 24639  			var uvA = new Vector2();
 24640  			var uvB = new Vector2();
 24641  			var uvC = new Vector2();
 24642  
 24643  			for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
 24644  
 24645  				a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
 24646  				b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
 24647  				c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
 24648  
 24649  				uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
 24650  				uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
 24651  				uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
 24652  
 24653  				centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
 24654  
 24655  				var azi = azimuth( centroid );
 24656  
 24657  				correctUV( uvA, j + 0, a, azi );
 24658  				correctUV( uvB, j + 2, b, azi );
 24659  				correctUV( uvC, j + 4, c, azi );
 24660  
 24661  			}
 24662  
 24663  		}
 24664  
 24665  		function correctUV( uv, stride, vector, azimuth ) {
 24666  
 24667  			if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
 24668  
 24669  				uvBuffer[ stride ] = uv.x - 1;
 24670  
 24671  			}
 24672  
 24673  			if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
 24674  
 24675  				uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
 24676  
 24677  			}
 24678  
 24679  		}
 24680  
 24681  		// Angle around the Y axis, counter-clockwise when looking from above.
 24682  
 24683  		function azimuth( vector ) {
 24684  
 24685  			return Math.atan2( vector.z, - vector.x );
 24686  
 24687  		}
 24688  
 24689  
 24690  		// Angle above the XZ plane.
 24691  
 24692  		function inclination( vector ) {
 24693  
 24694  			return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
 24695  
 24696  		}
 24697  
 24698  	}
 24699  
 24700  	PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 24701  	PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry;
 24702  
 24703  	/**
 24704  	 * @author timothypratley / https://github.com/timothypratley
 24705  	 */
 24706  
 24707  	function TetrahedronGeometry( radius, detail ) {
 24708  
 24709  		Geometry.call( this );
 24710  
 24711  		this.type = 'TetrahedronGeometry';
 24712  
 24713  		this.parameters = {
 24714  			radius: radius,
 24715  			detail: detail
 24716  		};
 24717  
 24718  		this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) );
 24719  		this.mergeVertices();
 24720  
 24721  	}
 24722  
 24723  	TetrahedronGeometry.prototype = Object.create( Geometry.prototype );
 24724  	TetrahedronGeometry.prototype.constructor = TetrahedronGeometry;
 24725  
 24726  	/**
 24727  	 * @author Mugen87 / https://github.com/Mugen87
 24728  	 */
 24729  
 24730  	function TetrahedronBufferGeometry( radius, detail ) {
 24731  
 24732  		var vertices = [
 24733  			1,  1,  1,   - 1, - 1,  1,   - 1,  1, - 1,    1, - 1, - 1
 24734  		];
 24735  
 24736  		var indices = [
 24737  			2,  1,  0,    0,  3,  2,    1,  3,  0,    2,  3,  1
 24738  		];
 24739  
 24740  		PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
 24741  
 24742  		this.type = 'TetrahedronBufferGeometry';
 24743  
 24744  		this.parameters = {
 24745  			radius: radius,
 24746  			detail: detail
 24747  		};
 24748  
 24749  	}
 24750  
 24751  	TetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
 24752  	TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry;
 24753  
 24754  	/**
 24755  	 * @author timothypratley / https://github.com/timothypratley
 24756  	 */
 24757  
 24758  	function OctahedronGeometry( radius, detail ) {
 24759  
 24760  		Geometry.call( this );
 24761  
 24762  		this.type = 'OctahedronGeometry';
 24763  
 24764  		this.parameters = {
 24765  			radius: radius,
 24766  			detail: detail
 24767  		};
 24768  
 24769  		this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) );
 24770  		this.mergeVertices();
 24771  
 24772  	}
 24773  
 24774  	OctahedronGeometry.prototype = Object.create( Geometry.prototype );
 24775  	OctahedronGeometry.prototype.constructor = OctahedronGeometry;
 24776  
 24777  	/**
 24778  	 * @author Mugen87 / https://github.com/Mugen87
 24779  	 */
 24780  
 24781  	function OctahedronBufferGeometry( radius, detail ) {
 24782  
 24783  		var vertices = [
 24784  			1, 0, 0,   - 1, 0, 0,    0, 1, 0,    0, - 1, 0,    0, 0, 1,    0, 0, - 1
 24785  		];
 24786  
 24787  		var indices = [
 24788  			0, 2, 4,    0, 4, 3,    0, 3, 5,    0, 5, 2,    1, 2, 5,    1, 5, 3,    1, 3, 4,    1, 4, 2
 24789  		];
 24790  
 24791  		PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
 24792  
 24793  		this.type = 'OctahedronBufferGeometry';
 24794  
 24795  		this.parameters = {
 24796  			radius: radius,
 24797  			detail: detail
 24798  		};
 24799  
 24800  	}
 24801  
 24802  	OctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
 24803  	OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry;
 24804  
 24805  	/**
 24806  	 * @author timothypratley / https://github.com/timothypratley
 24807  	 */
 24808  
 24809  	function IcosahedronGeometry( radius, detail ) {
 24810  
 24811  	 	Geometry.call( this );
 24812  
 24813  		this.type = 'IcosahedronGeometry';
 24814  
 24815  		this.parameters = {
 24816  			radius: radius,
 24817  			detail: detail
 24818  		};
 24819  
 24820  		this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) );
 24821  		this.mergeVertices();
 24822  
 24823  	}
 24824  
 24825  	IcosahedronGeometry.prototype = Object.create( Geometry.prototype );
 24826  	IcosahedronGeometry.prototype.constructor = IcosahedronGeometry;
 24827  
 24828  	/**
 24829  	 * @author Mugen87 / https://github.com/Mugen87
 24830  	 */
 24831  
 24832  	function IcosahedronBufferGeometry( radius, detail ) {
 24833  
 24834  		var t = ( 1 + Math.sqrt( 5 ) ) / 2;
 24835  
 24836  		var vertices = [
 24837  			- 1,  t,  0,    1,  t,  0,   - 1, - t,  0,    1, - t,  0,
 24838  			 0, - 1,  t,    0,  1,  t,    0, - 1, - t,    0,  1, - t,
 24839  			 t,  0, - 1,    t,  0,  1,   - t,  0, - 1,   - t,  0,  1
 24840  		];
 24841  
 24842  		var indices = [
 24843  			 0, 11,  5,    0,  5,  1,    0,  1,  7,    0,  7, 10,    0, 10, 11,
 24844  			 1,  5,  9,    5, 11,  4,   11, 10,  2,   10,  7,  6,    7,  1,  8,
 24845  			 3,  9,  4,    3,  4,  2,    3,  2,  6,    3,  6,  8,    3,  8,  9,
 24846  			 4,  9,  5,    2,  4, 11,    6,  2, 10,    8,  6,  7,    9,  8,  1
 24847  		];
 24848  
 24849  		PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
 24850  
 24851  		this.type = 'IcosahedronBufferGeometry';
 24852  
 24853  		this.parameters = {
 24854  			radius: radius,
 24855  			detail: detail
 24856  		};
 24857  
 24858  	}
 24859  
 24860  	IcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
 24861  	IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry;
 24862  
 24863  	/**
 24864  	 * @author Abe Pazos / https://hamoid.com
 24865  	 */
 24866  
 24867  	function DodecahedronGeometry( radius, detail ) {
 24868  
 24869  		Geometry.call( this );
 24870  
 24871  		this.type = 'DodecahedronGeometry';
 24872  
 24873  		this.parameters = {
 24874  			radius: radius,
 24875  			detail: detail
 24876  		};
 24877  
 24878  		this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) );
 24879  		this.mergeVertices();
 24880  
 24881  	}
 24882  
 24883  	DodecahedronGeometry.prototype = Object.create( Geometry.prototype );
 24884  	DodecahedronGeometry.prototype.constructor = DodecahedronGeometry;
 24885  
 24886  	/**
 24887  	 * @author Mugen87 / https://github.com/Mugen87
 24888  	 */
 24889  
 24890  	function DodecahedronBufferGeometry( radius, detail ) {
 24891  
 24892  		var t = ( 1 + Math.sqrt( 5 ) ) / 2;
 24893  		var r = 1 / t;
 24894  
 24895  		var vertices = [
 24896  
 24897  			// (±1, ±1, ±1)
 24898  			- 1, - 1, - 1,    - 1, - 1,  1,
 24899  			- 1,  1, - 1,    - 1,  1,  1,
 24900  			  1, - 1, - 1,     1, - 1,  1,
 24901  			  1,  1, - 1,     1,  1,  1,
 24902  
 24903  			// (0, ±1/φ, ±φ)
 24904  			 0, - r, - t,     0, - r,  t,
 24905  			 0,  r, - t,     0,  r,  t,
 24906  
 24907  			// (±1/φ, ±φ, 0)
 24908  			- r, - t,  0,    - r,  t,  0,
 24909  			 r, - t,  0,     r,  t,  0,
 24910  
 24911  			// (±φ, 0, ±1/φ)
 24912  			- t,  0, - r,     t,  0, - r,
 24913  			- t,  0,  r,     t,  0,  r
 24914  		];
 24915  
 24916  		var indices = [
 24917  			 3, 11,  7,      3,  7, 15,      3, 15, 13,
 24918  			 7, 19, 17,      7, 17,  6,      7,  6, 15,
 24919  			17,  4,  8,     17,  8, 10,     17, 10,  6,
 24920  			 8,  0, 16,      8, 16,  2,      8,  2, 10,
 24921  			 0, 12,  1,      0,  1, 18,      0, 18, 16,
 24922  			 6, 10,  2,      6,  2, 13,      6, 13, 15,
 24923  			 2, 16, 18,      2, 18,  3,      2,  3, 13,
 24924  			18,  1,  9,     18,  9, 11,     18, 11,  3,
 24925  			 4, 14, 12,      4, 12,  0,      4,  0,  8,
 24926  			11,  9,  5,     11,  5, 19,     11, 19,  7,
 24927  			19,  5, 14,     19, 14,  4,     19,  4, 17,
 24928  			 1, 12, 14,      1, 14,  5,      1,  5,  9
 24929  		];
 24930  
 24931  		PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
 24932  
 24933  		this.type = 'DodecahedronBufferGeometry';
 24934  
 24935  		this.parameters = {
 24936  			radius: radius,
 24937  			detail: detail
 24938  		};
 24939  
 24940  	}
 24941  
 24942  	DodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
 24943  	DodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry;
 24944  
 24945  	/**
 24946  	 * @author oosmoxiecode / https://github.com/oosmoxiecode
 24947  	 * @author WestLangley / https://github.com/WestLangley
 24948  	 * @author zz85 / https://github.com/zz85
 24949  	 * @author miningold / https://github.com/miningold
 24950  	 * @author jonobr1 / https://github.com/jonobr1
 24951  	 *
 24952  	 * Creates a tube which extrudes along a 3d spline.
 24953  	 */
 24954  
 24955  	function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) {
 24956  
 24957  		Geometry.call( this );
 24958  
 24959  		this.type = 'TubeGeometry';
 24960  
 24961  		this.parameters = {
 24962  			path: path,
 24963  			tubularSegments: tubularSegments,
 24964  			radius: radius,
 24965  			radialSegments: radialSegments,
 24966  			closed: closed
 24967  		};
 24968  
 24969  		if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' );
 24970  
 24971  		var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed );
 24972  
 24973  		// expose internals
 24974  
 24975  		this.tangents = bufferGeometry.tangents;
 24976  		this.normals = bufferGeometry.normals;
 24977  		this.binormals = bufferGeometry.binormals;
 24978  
 24979  		// create geometry
 24980  
 24981  		this.fromBufferGeometry( bufferGeometry );
 24982  		this.mergeVertices();
 24983  
 24984  	}
 24985  
 24986  	TubeGeometry.prototype = Object.create( Geometry.prototype );
 24987  	TubeGeometry.prototype.constructor = TubeGeometry;
 24988  
 24989  	/**
 24990  	 * @author Mugen87 / https://github.com/Mugen87
 24991  	 */
 24992  
 24993  	function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) {
 24994  
 24995  		BufferGeometry.call( this );
 24996  
 24997  		this.type = 'TubeBufferGeometry';
 24998  
 24999  		this.parameters = {
 25000  			path: path,
 25001  			tubularSegments: tubularSegments,
 25002  			radius: radius,
 25003  			radialSegments: radialSegments,
 25004  			closed: closed
 25005  		};
 25006  
 25007  		tubularSegments = tubularSegments || 64;
 25008  		radius = radius || 1;
 25009  		radialSegments = radialSegments || 8;
 25010  		closed = closed || false;
 25011  
 25012  		var frames = path.computeFrenetFrames( tubularSegments, closed );
 25013  
 25014  		// expose internals
 25015  
 25016  		this.tangents = frames.tangents;
 25017  		this.normals = frames.normals;
 25018  		this.binormals = frames.binormals;
 25019  
 25020  		// helper variables
 25021  
 25022  		var vertex = new Vector3();
 25023  		var normal = new Vector3();
 25024  		var uv = new Vector2();
 25025  
 25026  		var i, j;
 25027  
 25028  		// buffer
 25029  
 25030  		var vertices = [];
 25031  		var normals = [];
 25032  		var uvs = [];
 25033  		var indices = [];
 25034  
 25035  		// create buffer data
 25036  
 25037  		generateBufferData();
 25038  
 25039  		// build geometry
 25040  
 25041  		this.setIndex( indices );
 25042  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 25043  		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
 25044  		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 25045  
 25046  		// functions
 25047  
 25048  		function generateBufferData() {
 25049  
 25050  			for ( i = 0; i < tubularSegments; i ++ ) {
 25051  
 25052  				generateSegment( i );
 25053  
 25054  			}
 25055  
 25056  			// if the geometry is not closed, generate the last row of vertices and normals
 25057  			// at the regular position on the given path
 25058  			//
 25059  			// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
 25060  
 25061  			generateSegment( ( closed === false ) ? tubularSegments : 0 );
 25062  
 25063  			// uvs are generated in a separate function.
 25064  			// this makes it easy compute correct values for closed geometries
 25065  
 25066  			generateUVs();
 25067  
 25068  			// finally create faces
 25069  
 25070  			generateIndices();
 25071  
 25072  		}
 25073  
 25074  		function generateSegment( i ) {
 25075  
 25076  			// we use getPointAt to sample evenly distributed points from the given path
 25077  
 25078  			var P = path.getPointAt( i / tubularSegments );
 25079  
 25080  			// retrieve corresponding normal and binormal
 25081  
 25082  			var N = frames.normals[ i ];
 25083  			var B = frames.binormals[ i ];
 25084  
 25085  			// generate normals and vertices for the current segment
 25086  
 25087  			for ( j = 0; j <= radialSegments; j ++ ) {
 25088  
 25089  				var v = j / radialSegments * Math.PI * 2;
 25090  
 25091  				var sin =   Math.sin( v );
 25092  				var cos = - Math.cos( v );
 25093  
 25094  				// normal
 25095  
 25096  				normal.x = ( cos * N.x + sin * B.x );
 25097  				normal.y = ( cos * N.y + sin * B.y );
 25098  				normal.z = ( cos * N.z + sin * B.z );
 25099  				normal.normalize();
 25100  
 25101  				normals.push( normal.x, normal.y, normal.z );
 25102  
 25103  				// vertex
 25104  
 25105  				vertex.x = P.x + radius * normal.x;
 25106  				vertex.y = P.y + radius * normal.y;
 25107  				vertex.z = P.z + radius * normal.z;
 25108  
 25109  				vertices.push( vertex.x, vertex.y, vertex.z );
 25110  
 25111  			}
 25112  
 25113  		}
 25114  
 25115  		function generateIndices() {
 25116  
 25117  			for ( j = 1; j <= tubularSegments; j ++ ) {
 25118  
 25119  				for ( i = 1; i <= radialSegments; i ++ ) {
 25120  
 25121  					var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
 25122  					var b = ( radialSegments + 1 ) * j + ( i - 1 );
 25123  					var c = ( radialSegments + 1 ) * j + i;
 25124  					var d = ( radialSegments + 1 ) * ( j - 1 ) + i;
 25125  
 25126  					// faces
 25127  
 25128  					indices.push( a, b, d );
 25129  					indices.push( b, c, d );
 25130  
 25131  				}
 25132  
 25133  			}
 25134  
 25135  		}
 25136  
 25137  		function generateUVs() {
 25138  
 25139  			for ( i = 0; i <= tubularSegments; i ++ ) {
 25140  
 25141  				for ( j = 0; j <= radialSegments; j ++ ) {
 25142  
 25143  					uv.x = i / tubularSegments;
 25144  					uv.y = j / radialSegments;
 25145  
 25146  					uvs.push( uv.x, uv.y );
 25147  
 25148  				}
 25149  
 25150  			}
 25151  
 25152  		}
 25153  
 25154  	}
 25155  
 25156  	TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 25157  	TubeBufferGeometry.prototype.constructor = TubeBufferGeometry;
 25158  
 25159  	/**
 25160  	 * @author oosmoxiecode
 25161  	 */
 25162  
 25163  	function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) {
 25164  
 25165  		Geometry.call( this );
 25166  
 25167  		this.type = 'TorusKnotGeometry';
 25168  
 25169  		this.parameters = {
 25170  			radius: radius,
 25171  			tube: tube,
 25172  			tubularSegments: tubularSegments,
 25173  			radialSegments: radialSegments,
 25174  			p: p,
 25175  			q: q
 25176  		};
 25177  
 25178  		if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' );
 25179  
 25180  		this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) );
 25181  		this.mergeVertices();
 25182  
 25183  	}
 25184  
 25185  	TorusKnotGeometry.prototype = Object.create( Geometry.prototype );
 25186  	TorusKnotGeometry.prototype.constructor = TorusKnotGeometry;
 25187  
 25188  	/**
 25189  	 * @author Mugen87 / https://github.com/Mugen87
 25190  	 * see: http://www.blackpawn.com/texts/pqtorus/
 25191  	 */
 25192  
 25193  	function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) {
 25194  
 25195  		BufferGeometry.call( this );
 25196  
 25197  		this.type = 'TorusKnotBufferGeometry';
 25198  
 25199  		this.parameters = {
 25200  			radius: radius,
 25201  			tube: tube,
 25202  			tubularSegments: tubularSegments,
 25203  			radialSegments: radialSegments,
 25204  			p: p,
 25205  			q: q
 25206  		};
 25207  
 25208  		radius = radius || 100;
 25209  		tube = tube || 40;
 25210  		tubularSegments = Math.floor( tubularSegments ) || 64;
 25211  		radialSegments = Math.floor( radialSegments ) || 8;
 25212  		p = p || 2;
 25213  		q = q || 3;
 25214  
 25215  		// buffers
 25216  
 25217  		var indices = [];
 25218  		var vertices = [];
 25219  		var normals = [];
 25220  		var uvs = [];
 25221  
 25222  		// helper variables
 25223  
 25224  		var i, j;
 25225  
 25226  		var vertex = new Vector3();
 25227  		var normal = new Vector3();
 25228  		var uv = new Vector2();
 25229  
 25230  		var P1 = new Vector3();
 25231  		var P2 = new Vector3();
 25232  
 25233  		var B = new Vector3();
 25234  		var T = new Vector3();
 25235  		var N = new Vector3();
 25236  
 25237  		// generate vertices, normals and uvs
 25238  
 25239  		for ( i = 0; i <= tubularSegments; ++ i ) {
 25240  
 25241  			// the radian "u" is used to calculate the position on the torus curve of the current tubular segement
 25242  
 25243  			var u = i / tubularSegments * p * Math.PI * 2;
 25244  
 25245  			// now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
 25246  			// these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
 25247  
 25248  			calculatePositionOnCurve( u, p, q, radius, P1 );
 25249  			calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );
 25250  
 25251  			// calculate orthonormal basis
 25252  
 25253  			T.subVectors( P2, P1 );
 25254  			N.addVectors( P2, P1 );
 25255  			B.crossVectors( T, N );
 25256  			N.crossVectors( B, T );
 25257  
 25258  			// normalize B, N. T can be ignored, we don't use it
 25259  
 25260  			B.normalize();
 25261  			N.normalize();
 25262  
 25263  			for ( j = 0; j <= radialSegments; ++ j ) {
 25264  
 25265  				// now calculate the vertices. they are nothing more than an extrusion of the torus curve.
 25266  				// because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
 25267  
 25268  				var v = j / radialSegments * Math.PI * 2;
 25269  				var cx = - tube * Math.cos( v );
 25270  				var cy = tube * Math.sin( v );
 25271  
 25272  				// now calculate the final vertex position.
 25273  				// first we orient the extrusion with our basis vectos, then we add it to the current position on the curve
 25274  
 25275  				vertex.x = P1.x + ( cx * N.x + cy * B.x );
 25276  				vertex.y = P1.y + ( cx * N.y + cy * B.y );
 25277  				vertex.z = P1.z + ( cx * N.z + cy * B.z );
 25278  
 25279  				vertices.push( vertex.x, vertex.y, vertex.z );
 25280  
 25281  				// normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
 25282  
 25283  				normal.subVectors( vertex, P1 ).normalize();
 25284  
 25285  				normals.push( normal.x, normal.y, normal.z );
 25286  
 25287  				// uv
 25288  
 25289  				uvs.push( i / tubularSegments );
 25290  				uvs.push( j / radialSegments );
 25291  
 25292  			}
 25293  
 25294  		}
 25295  
 25296  		// generate indices
 25297  
 25298  		for ( j = 1; j <= tubularSegments; j ++ ) {
 25299  
 25300  			for ( i = 1; i <= radialSegments; i ++ ) {
 25301  
 25302  				// indices
 25303  
 25304  				var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
 25305  				var b = ( radialSegments + 1 ) * j + ( i - 1 );
 25306  				var c = ( radialSegments + 1 ) * j + i;
 25307  				var d = ( radialSegments + 1 ) * ( j - 1 ) + i;
 25308  
 25309  				// faces
 25310  
 25311  				indices.push( a, b, d );
 25312  				indices.push( b, c, d );
 25313  
 25314  			}
 25315  
 25316  		}
 25317  
 25318  		// build geometry
 25319  
 25320  		this.setIndex( indices );
 25321  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 25322  		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
 25323  		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 25324  
 25325  		// this function calculates the current position on the torus curve
 25326  
 25327  		function calculatePositionOnCurve( u, p, q, radius, position ) {
 25328  
 25329  			var cu = Math.cos( u );
 25330  			var su = Math.sin( u );
 25331  			var quOverP = q / p * u;
 25332  			var cs = Math.cos( quOverP );
 25333  
 25334  			position.x = radius * ( 2 + cs ) * 0.5 * cu;
 25335  			position.y = radius * ( 2 + cs ) * su * 0.5;
 25336  			position.z = radius * Math.sin( quOverP ) * 0.5;
 25337  
 25338  		}
 25339  
 25340  	}
 25341  
 25342  	TorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 25343  	TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry;
 25344  
 25345  	/**
 25346  	 * @author oosmoxiecode
 25347  	 * @author mrdoob / http://mrdoob.com/
 25348  	 * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888
 25349  	 */
 25350  
 25351  	function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) {
 25352  
 25353  		Geometry.call( this );
 25354  
 25355  		this.type = 'TorusGeometry';
 25356  
 25357  		this.parameters = {
 25358  			radius: radius,
 25359  			tube: tube,
 25360  			radialSegments: radialSegments,
 25361  			tubularSegments: tubularSegments,
 25362  			arc: arc
 25363  		};
 25364  
 25365  		this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) );
 25366  
 25367  	}
 25368  
 25369  	TorusGeometry.prototype = Object.create( Geometry.prototype );
 25370  	TorusGeometry.prototype.constructor = TorusGeometry;
 25371  
 25372  	/**
 25373  	 * @author Mugen87 / https://github.com/Mugen87
 25374  	 */
 25375  
 25376  	function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) {
 25377  
 25378  		BufferGeometry.call( this );
 25379  
 25380  		this.type = 'TorusBufferGeometry';
 25381  
 25382  		this.parameters = {
 25383  			radius: radius,
 25384  			tube: tube,
 25385  			radialSegments: radialSegments,
 25386  			tubularSegments: tubularSegments,
 25387  			arc: arc
 25388  		};
 25389  
 25390  		radius = radius || 100;
 25391  		tube = tube || 40;
 25392  		radialSegments = Math.floor( radialSegments ) || 8;
 25393  		tubularSegments = Math.floor( tubularSegments ) || 6;
 25394  		arc = arc || Math.PI * 2;
 25395  
 25396  		// buffers
 25397  
 25398  		var indices = [];
 25399  		var vertices = [];
 25400  		var normals = [];
 25401  		var uvs = [];
 25402  
 25403  		// helper variables
 25404  
 25405  		var center = new Vector3();
 25406  		var vertex = new Vector3();
 25407  		var normal = new Vector3();
 25408  
 25409  		var j, i;
 25410  
 25411  		// generate vertices, normals and uvs
 25412  
 25413  		for ( j = 0; j <= radialSegments; j ++ ) {
 25414  
 25415  			for ( i = 0; i <= tubularSegments; i ++ ) {
 25416  
 25417  				var u = i / tubularSegments * arc;
 25418  				var v = j / radialSegments * Math.PI * 2;
 25419  
 25420  				// vertex
 25421  
 25422  				vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
 25423  				vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
 25424  				vertex.z = tube * Math.sin( v );
 25425  
 25426  				vertices.push( vertex.x, vertex.y, vertex.z );
 25427  
 25428  				// normal
 25429  
 25430  				center.x = radius * Math.cos( u );
 25431  				center.y = radius * Math.sin( u );
 25432  				normal.subVectors( vertex, center ).normalize();
 25433  
 25434  				normals.push( normal.x, normal.y, normal.z );
 25435  
 25436  				// uv
 25437  
 25438  				uvs.push( i / tubularSegments );
 25439  				uvs.push( j / radialSegments );
 25440  
 25441  			}
 25442  
 25443  		}
 25444  
 25445  		// generate indices
 25446  
 25447  		for ( j = 1; j <= radialSegments; j ++ ) {
 25448  
 25449  			for ( i = 1; i <= tubularSegments; i ++ ) {
 25450  
 25451  				// indices
 25452  
 25453  				var a = ( tubularSegments + 1 ) * j + i - 1;
 25454  				var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
 25455  				var c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
 25456  				var d = ( tubularSegments + 1 ) * j + i;
 25457  
 25458  				// faces
 25459  
 25460  				indices.push( a, b, d );
 25461  				indices.push( b, c, d );
 25462  
 25463  			}
 25464  
 25465  		}
 25466  
 25467  		// build geometry
 25468  
 25469  		this.setIndex( indices );
 25470  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 25471  		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
 25472  		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 25473  
 25474  	}
 25475  
 25476  	TorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 25477  	TorusBufferGeometry.prototype.constructor = TorusBufferGeometry;
 25478  
 25479  	/**
 25480  	 * @author zz85 / http://www.lab4games.net/zz85/blog
 25481  	 */
 25482  
 25483  	var ShapeUtils = {
 25484  
 25485  		// calculate area of the contour polygon
 25486  
 25487  		area: function ( contour ) {
 25488  
 25489  			var n = contour.length;
 25490  			var a = 0.0;
 25491  
 25492  			for ( var p = n - 1, q = 0; q < n; p = q ++ ) {
 25493  
 25494  				a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
 25495  
 25496  			}
 25497  
 25498  			return a * 0.5;
 25499  
 25500  		},
 25501  
 25502  		triangulate: ( function () {
 25503  
 25504  			/**
 25505  			 * This code is a quick port of code written in C++ which was submitted to
 25506  			 * flipcode.com by John W. Ratcliff  // July 22, 2000
 25507  			 * See original code and more information here:
 25508  			 * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
 25509  			 *
 25510  			 * ported to actionscript by Zevan Rosser
 25511  			 * www.actionsnippet.com
 25512  			 *
 25513  			 * ported to javascript by Joshua Koo
 25514  			 * http://www.lab4games.net/zz85/blog
 25515  			 *
 25516  			 */
 25517  
 25518  			function snip( contour, u, v, w, n, verts ) {
 25519  
 25520  				var p;
 25521  				var ax, ay, bx, by;
 25522  				var cx, cy, px, py;
 25523  
 25524  				ax = contour[ verts[ u ] ].x;
 25525  				ay = contour[ verts[ u ] ].y;
 25526  
 25527  				bx = contour[ verts[ v ] ].x;
 25528  				by = contour[ verts[ v ] ].y;
 25529  
 25530  				cx = contour[ verts[ w ] ].x;
 25531  				cy = contour[ verts[ w ] ].y;
 25532  
 25533  				if ( ( bx - ax ) * ( cy - ay ) - ( by - ay ) * ( cx - ax ) <= 0 ) return false;
 25534  
 25535  				var aX, aY, bX, bY, cX, cY;
 25536  				var apx, apy, bpx, bpy, cpx, cpy;
 25537  				var cCROSSap, bCROSScp, aCROSSbp;
 25538  
 25539  				aX = cx - bx;  aY = cy - by;
 25540  				bX = ax - cx;  bY = ay - cy;
 25541  				cX = bx - ax;  cY = by - ay;
 25542  
 25543  				for ( p = 0; p < n; p ++ ) {
 25544  
 25545  					px = contour[ verts[ p ] ].x;
 25546  					py = contour[ verts[ p ] ].y;
 25547  
 25548  					if ( ( ( px === ax ) && ( py === ay ) ) ||
 25549  						 ( ( px === bx ) && ( py === by ) ) ||
 25550  						 ( ( px === cx ) && ( py === cy ) ) )	continue;
 25551  
 25552  					apx = px - ax;  apy = py - ay;
 25553  					bpx = px - bx;  bpy = py - by;
 25554  					cpx = px - cx;  cpy = py - cy;
 25555  
 25556  					// see if p is inside triangle abc
 25557  
 25558  					aCROSSbp = aX * bpy - aY * bpx;
 25559  					cCROSSap = cX * apy - cY * apx;
 25560  					bCROSScp = bX * cpy - bY * cpx;
 25561  
 25562  					if ( ( aCROSSbp >= - Number.EPSILON ) && ( bCROSScp >= - Number.EPSILON ) && ( cCROSSap >= - Number.EPSILON ) ) return false;
 25563  
 25564  				}
 25565  
 25566  				return true;
 25567  
 25568  			}
 25569  
 25570  			// takes in an contour array and returns
 25571  
 25572  			return function triangulate( contour, indices ) {
 25573  
 25574  				var n = contour.length;
 25575  
 25576  				if ( n < 3 ) return null;
 25577  
 25578  				var result = [],
 25579  					verts = [],
 25580  					vertIndices = [];
 25581  
 25582  				/* we want a counter-clockwise polygon in verts */
 25583  
 25584  				var u, v, w;
 25585  
 25586  				if ( ShapeUtils.area( contour ) > 0.0 ) {
 25587  
 25588  					for ( v = 0; v < n; v ++ ) verts[ v ] = v;
 25589  
 25590  				} else {
 25591  
 25592  					for ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v;
 25593  
 25594  				}
 25595  
 25596  				var nv = n;
 25597  
 25598  				/*  remove nv - 2 vertices, creating 1 triangle every time */
 25599  
 25600  				var count = 2 * nv;   /* error detection */
 25601  
 25602  				for ( v = nv - 1; nv > 2; ) {
 25603  
 25604  					/* if we loop, it is probably a non-simple polygon */
 25605  
 25606  					if ( ( count -- ) <= 0 ) {
 25607  
 25608  						//** Triangulate: ERROR - probable bad polygon!
 25609  
 25610  						//throw ( "Warning, unable to triangulate polygon!" );
 25611  						//return null;
 25612  						// Sometimes warning is fine, especially polygons are triangulated in reverse.
 25613  						console.warn( 'THREE.ShapeUtils: Unable to triangulate polygon! in triangulate()' );
 25614  
 25615  						if ( indices ) return vertIndices;
 25616  						return result;
 25617  
 25618  					}
 25619  
 25620  					/* three consecutive vertices in current polygon, <u,v,w> */
 25621  
 25622  					u = v; 	 	if ( nv <= u ) u = 0;     /* previous */
 25623  					v = u + 1;  if ( nv <= v ) v = 0;     /* new v    */
 25624  					w = v + 1;  if ( nv <= w ) w = 0;     /* next     */
 25625  
 25626  					if ( snip( contour, u, v, w, nv, verts ) ) {
 25627  
 25628  						var a, b, c, s, t;
 25629  
 25630  						/* true names of the vertices */
 25631  
 25632  						a = verts[ u ];
 25633  						b = verts[ v ];
 25634  						c = verts[ w ];
 25635  
 25636  						/* output Triangle */
 25637  
 25638  						result.push( [ contour[ a ],
 25639  							contour[ b ],
 25640  							contour[ c ] ] );
 25641  
 25642  
 25643  						vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );
 25644  
 25645  						/* remove v from the remaining polygon */
 25646  
 25647  						for ( s = v, t = v + 1; t < nv; s ++, t ++ ) {
 25648  
 25649  							verts[ s ] = verts[ t ];
 25650  
 25651  						}
 25652  
 25653  						nv --;
 25654  
 25655  						/* reset error detection counter */
 25656  
 25657  						count = 2 * nv;
 25658  
 25659  					}
 25660  
 25661  				}
 25662  
 25663  				if ( indices ) return vertIndices;
 25664  				return result;
 25665  
 25666  			}
 25667  
 25668  		} )(),
 25669  
 25670  		triangulateShape: function ( contour, holes ) {
 25671  
 25672  			function removeDupEndPts(points) {
 25673  
 25674  				var l = points.length;
 25675  
 25676  				if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {
 25677  
 25678  					points.pop();
 25679  
 25680  				}
 25681  
 25682  			}
 25683  
 25684  			removeDupEndPts( contour );
 25685  			holes.forEach( removeDupEndPts );
 25686  
 25687  			function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) {
 25688  
 25689  				// inOtherPt needs to be collinear to the inSegment
 25690  				if ( inSegPt1.x !== inSegPt2.x ) {
 25691  
 25692  					if ( inSegPt1.x < inSegPt2.x ) {
 25693  
 25694  						return	( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) );
 25695  
 25696  					} else {
 25697  
 25698  						return	( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) );
 25699  
 25700  					}
 25701  
 25702  				} else {
 25703  
 25704  					if ( inSegPt1.y < inSegPt2.y ) {
 25705  
 25706  						return	( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) );
 25707  
 25708  					} else {
 25709  
 25710  						return	( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) );
 25711  
 25712  					}
 25713  
 25714  				}
 25715  
 25716  			}
 25717  
 25718  			function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) {
 25719  
 25720  				var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x,   seg1dy = inSeg1Pt2.y - inSeg1Pt1.y;
 25721  				var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x,   seg2dy = inSeg2Pt2.y - inSeg2Pt1.y;
 25722  
 25723  				var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x;
 25724  				var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y;
 25725  
 25726  				var limit		= seg1dy * seg2dx - seg1dx * seg2dy;
 25727  				var perpSeg1	= seg1dy * seg1seg2dx - seg1dx * seg1seg2dy;
 25728  
 25729  				if ( Math.abs( limit ) > Number.EPSILON ) {
 25730  
 25731  					// not parallel
 25732  
 25733  					var perpSeg2;
 25734  					if ( limit > 0 ) {
 25735  
 25736  						if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) 		return [];
 25737  						perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;
 25738  						if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) 		return [];
 25739  
 25740  					} else {
 25741  
 25742  						if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) 		return [];
 25743  						perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;
 25744  						if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) 		return [];
 25745  
 25746  					}
 25747  
 25748  					// i.e. to reduce rounding errors
 25749  					// intersection at endpoint of segment#1?
 25750  					if ( perpSeg2 === 0 ) {
 25751  
 25752  						if ( ( inExcludeAdjacentSegs ) &&
 25753  							 ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) )		return [];
 25754  						return [ inSeg1Pt1 ];
 25755  
 25756  					}
 25757  					if ( perpSeg2 === limit ) {
 25758  
 25759  						if ( ( inExcludeAdjacentSegs ) &&
 25760  							 ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) )		return [];
 25761  						return [ inSeg1Pt2 ];
 25762  
 25763  					}
 25764  					// intersection at endpoint of segment#2?
 25765  					if ( perpSeg1 === 0 )		return [ inSeg2Pt1 ];
 25766  					if ( perpSeg1 === limit )	return [ inSeg2Pt2 ];
 25767  
 25768  					// return real intersection point
 25769  					var factorSeg1 = perpSeg2 / limit;
 25770  					return	[ { x: inSeg1Pt1.x + factorSeg1 * seg1dx,
 25771  								y: inSeg1Pt1.y + factorSeg1 * seg1dy } ];
 25772  
 25773  				} else {
 25774  
 25775  					// parallel or collinear
 25776  					if ( ( perpSeg1 !== 0 ) ||
 25777  						 ( seg2dy * seg1seg2dx !== seg2dx * seg1seg2dy ) ) 			return [];
 25778  
 25779  					// they are collinear or degenerate
 25780  					var seg1Pt = ( ( seg1dx === 0 ) && ( seg1dy === 0 ) );	// segment1 is just a point?
 25781  					var seg2Pt = ( ( seg2dx === 0 ) && ( seg2dy === 0 ) );	// segment2 is just a point?
 25782  					// both segments are points
 25783  					if ( seg1Pt && seg2Pt ) {
 25784  
 25785  						if ( ( inSeg1Pt1.x !== inSeg2Pt1.x ) ||
 25786  							 ( inSeg1Pt1.y !== inSeg2Pt1.y ) )		return [];	// they are distinct  points
 25787  						return [ inSeg1Pt1 ];                 						// they are the same point
 25788  
 25789  					}
 25790  					// segment#1  is a single point
 25791  					if ( seg1Pt ) {
 25792  
 25793  						if ( ! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) )		return [];		// but not in segment#2
 25794  						return [ inSeg1Pt1 ];
 25795  
 25796  					}
 25797  					// segment#2  is a single point
 25798  					if ( seg2Pt ) {
 25799  
 25800  						if ( ! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) )		return [];		// but not in segment#1
 25801  						return [ inSeg2Pt1 ];
 25802  
 25803  					}
 25804  
 25805  					// they are collinear segments, which might overlap
 25806  					var seg1min, seg1max, seg1minVal, seg1maxVal;
 25807  					var seg2min, seg2max, seg2minVal, seg2maxVal;
 25808  					if ( seg1dx !== 0 ) {
 25809  
 25810  						// the segments are NOT on a vertical line
 25811  						if ( inSeg1Pt1.x < inSeg1Pt2.x ) {
 25812  
 25813  							seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x;
 25814  							seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x;
 25815  
 25816  						} else {
 25817  
 25818  							seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x;
 25819  							seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x;
 25820  
 25821  						}
 25822  						if ( inSeg2Pt1.x < inSeg2Pt2.x ) {
 25823  
 25824  							seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x;
 25825  							seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x;
 25826  
 25827  						} else {
 25828  
 25829  							seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x;
 25830  							seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x;
 25831  
 25832  						}
 25833  
 25834  					} else {
 25835  
 25836  						// the segments are on a vertical line
 25837  						if ( inSeg1Pt1.y < inSeg1Pt2.y ) {
 25838  
 25839  							seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y;
 25840  							seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y;
 25841  
 25842  						} else {
 25843  
 25844  							seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y;
 25845  							seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y;
 25846  
 25847  						}
 25848  						if ( inSeg2Pt1.y < inSeg2Pt2.y ) {
 25849  
 25850  							seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y;
 25851  							seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y;
 25852  
 25853  						} else {
 25854  
 25855  							seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y;
 25856  							seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y;
 25857  
 25858  						}
 25859  
 25860  					}
 25861  					if ( seg1minVal <= seg2minVal ) {
 25862  
 25863  						if ( seg1maxVal <  seg2minVal )	return [];
 25864  						if ( seg1maxVal === seg2minVal )	{
 25865  
 25866  							if ( inExcludeAdjacentSegs )		return [];
 25867  							return [ seg2min ];
 25868  
 25869  						}
 25870  						if ( seg1maxVal <= seg2maxVal )	return [ seg2min, seg1max ];
 25871  						return	[ seg2min, seg2max ];
 25872  
 25873  					} else {
 25874  
 25875  						if ( seg1minVal >  seg2maxVal )	return [];
 25876  						if ( seg1minVal === seg2maxVal )	{
 25877  
 25878  							if ( inExcludeAdjacentSegs )		return [];
 25879  							return [ seg1min ];
 25880  
 25881  						}
 25882  						if ( seg1maxVal <= seg2maxVal )	return [ seg1min, seg1max ];
 25883  						return	[ seg1min, seg2max ];
 25884  
 25885  					}
 25886  
 25887  				}
 25888  
 25889  			}
 25890  
 25891  			function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) {
 25892  
 25893  				// The order of legs is important
 25894  
 25895  				// translation of all points, so that Vertex is at (0,0)
 25896  				var legFromPtX	= inLegFromPt.x - inVertex.x,  legFromPtY	= inLegFromPt.y - inVertex.y;
 25897  				var legToPtX	= inLegToPt.x	- inVertex.x,  legToPtY		= inLegToPt.y	- inVertex.y;
 25898  				var otherPtX	= inOtherPt.x	- inVertex.x,  otherPtY		= inOtherPt.y	- inVertex.y;
 25899  
 25900  				// main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg.
 25901  				var from2toAngle	= legFromPtX * legToPtY - legFromPtY * legToPtX;
 25902  				var from2otherAngle	= legFromPtX * otherPtY - legFromPtY * otherPtX;
 25903  
 25904  				if ( Math.abs( from2toAngle ) > Number.EPSILON ) {
 25905  
 25906  					// angle != 180 deg.
 25907  
 25908  					var other2toAngle		= otherPtX * legToPtY - otherPtY * legToPtX;
 25909  					// console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle );
 25910  
 25911  					if ( from2toAngle > 0 ) {
 25912  
 25913  						// main angle < 180 deg.
 25914  						return	( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) );
 25915  
 25916  					} else {
 25917  
 25918  						// main angle > 180 deg.
 25919  						return	( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) );
 25920  
 25921  					}
 25922  
 25923  				} else {
 25924  
 25925  					// angle == 180 deg.
 25926  					// console.log( "from2to: 180 deg., from2other: " + from2otherAngle  );
 25927  					return	( from2otherAngle > 0 );
 25928  
 25929  				}
 25930  
 25931  			}
 25932  
 25933  
 25934  			function removeHoles( contour, holes ) {
 25935  
 25936  				var shape = contour.concat(); // work on this shape
 25937  				var hole;
 25938  
 25939  				function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) {
 25940  
 25941  					// Check if hole point lies within angle around shape point
 25942  					var lastShapeIdx = shape.length - 1;
 25943  
 25944  					var prevShapeIdx = inShapeIdx - 1;
 25945  					if ( prevShapeIdx < 0 )			prevShapeIdx = lastShapeIdx;
 25946  
 25947  					var nextShapeIdx = inShapeIdx + 1;
 25948  					if ( nextShapeIdx > lastShapeIdx )	nextShapeIdx = 0;
 25949  
 25950  					var insideAngle = isPointInsideAngle( shape[ inShapeIdx ], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[ inHoleIdx ] );
 25951  					if ( ! insideAngle ) {
 25952  
 25953  						// console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y );
 25954  						return	false;
 25955  
 25956  					}
 25957  
 25958  					// Check if shape point lies within angle around hole point
 25959  					var lastHoleIdx = hole.length - 1;
 25960  
 25961  					var prevHoleIdx = inHoleIdx - 1;
 25962  					if ( prevHoleIdx < 0 )			prevHoleIdx = lastHoleIdx;
 25963  
 25964  					var nextHoleIdx = inHoleIdx + 1;
 25965  					if ( nextHoleIdx > lastHoleIdx )	nextHoleIdx = 0;
 25966  
 25967  					insideAngle = isPointInsideAngle( hole[ inHoleIdx ], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[ inShapeIdx ] );
 25968  					if ( ! insideAngle ) {
 25969  
 25970  						// console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y );
 25971  						return	false;
 25972  
 25973  					}
 25974  
 25975  					return	true;
 25976  
 25977  				}
 25978  
 25979  				function intersectsShapeEdge( inShapePt, inHolePt ) {
 25980  
 25981  					// checks for intersections with shape edges
 25982  					var sIdx, nextIdx, intersection;
 25983  					for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) {
 25984  
 25985  						nextIdx = sIdx + 1; nextIdx %= shape.length;
 25986  						intersection = intersect_segments_2D( inShapePt, inHolePt, shape[ sIdx ], shape[ nextIdx ], true );
 25987  						if ( intersection.length > 0 )		return	true;
 25988  
 25989  					}
 25990  
 25991  					return	false;
 25992  
 25993  				}
 25994  
 25995  				var indepHoles = [];
 25996  
 25997  				function intersectsHoleEdge( inShapePt, inHolePt ) {
 25998  
 25999  					// checks for intersections with hole edges
 26000  					var ihIdx, chkHole,
 26001  						hIdx, nextIdx, intersection;
 26002  					for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) {
 26003  
 26004  						chkHole = holes[ indepHoles[ ihIdx ]];
 26005  						for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) {
 26006  
 26007  							nextIdx = hIdx + 1; nextIdx %= chkHole.length;
 26008  							intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[ hIdx ], chkHole[ nextIdx ], true );
 26009  							if ( intersection.length > 0 )		return	true;
 26010  
 26011  						}
 26012  
 26013  					}
 26014  					return	false;
 26015  
 26016  				}
 26017  
 26018  				var holeIndex, shapeIndex,
 26019  					shapePt, holePt,
 26020  					holeIdx, cutKey, failedCuts = [],
 26021  					tmpShape1, tmpShape2,
 26022  					tmpHole1, tmpHole2;
 26023  
 26024  				for ( var h = 0, hl = holes.length; h < hl; h ++ ) {
 26025  
 26026  					indepHoles.push( h );
 26027  
 26028  				}
 26029  
 26030  				var minShapeIndex = 0;
 26031  				var counter = indepHoles.length * 2;
 26032  				while ( indepHoles.length > 0 ) {
 26033  
 26034  					counter --;
 26035  					if ( counter < 0 ) {
 26036  
 26037  						console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" );
 26038  						break;
 26039  
 26040  					}
 26041  
 26042  					// search for shape-vertex and hole-vertex,
 26043  					// which can be connected without intersections
 26044  					for ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) {
 26045  
 26046  						shapePt = shape[ shapeIndex ];
 26047  						holeIndex	= - 1;
 26048  
 26049  						// search for hole which can be reached without intersections
 26050  						for ( var h = 0; h < indepHoles.length; h ++ ) {
 26051  
 26052  							holeIdx = indepHoles[ h ];
 26053  
 26054  							// prevent multiple checks
 26055  							cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx;
 26056  							if ( failedCuts[ cutKey ] !== undefined )			continue;
 26057  
 26058  							hole = holes[ holeIdx ];
 26059  							for ( var h2 = 0; h2 < hole.length; h2 ++ ) {
 26060  
 26061  								holePt = hole[ h2 ];
 26062  								if ( ! isCutLineInsideAngles( shapeIndex, h2 ) )		continue;
 26063  								if ( intersectsShapeEdge( shapePt, holePt ) )		continue;
 26064  								if ( intersectsHoleEdge( shapePt, holePt ) )		continue;
 26065  
 26066  								holeIndex = h2;
 26067  								indepHoles.splice( h, 1 );
 26068  
 26069  								tmpShape1 = shape.slice( 0, shapeIndex + 1 );
 26070  								tmpShape2 = shape.slice( shapeIndex );
 26071  								tmpHole1 = hole.slice( holeIndex );
 26072  								tmpHole2 = hole.slice( 0, holeIndex + 1 );
 26073  
 26074  								shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );
 26075  
 26076  								minShapeIndex = shapeIndex;
 26077  
 26078  								// Debug only, to show the selected cuts
 26079  								// glob_CutLines.push( [ shapePt, holePt ] );
 26080  
 26081  								break;
 26082  
 26083  							}
 26084  							if ( holeIndex >= 0 )	break;		// hole-vertex found
 26085  
 26086  							failedCuts[ cutKey ] = true;			// remember failure
 26087  
 26088  						}
 26089  						if ( holeIndex >= 0 )	break;		// hole-vertex found
 26090  
 26091  					}
 26092  
 26093  				}
 26094  
 26095  				return shape; 			/* shape with no holes */
 26096  
 26097  			}
 26098  
 26099  
 26100  			var i, il, f, face,
 26101  				key, index,
 26102  				allPointsMap = {};
 26103  
 26104  			// To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.
 26105  
 26106  			var allpoints = contour.concat();
 26107  
 26108  			for ( var h = 0, hl = holes.length; h < hl; h ++ ) {
 26109  
 26110  				Array.prototype.push.apply( allpoints, holes[ h ] );
 26111  
 26112  			}
 26113  
 26114  			//console.log( "allpoints",allpoints, allpoints.length );
 26115  
 26116  			// prepare all points map
 26117  
 26118  			for ( i = 0, il = allpoints.length; i < il; i ++ ) {
 26119  
 26120  				key = allpoints[ i ].x + ":" + allpoints[ i ].y;
 26121  
 26122  				if ( allPointsMap[ key ] !== undefined ) {
 26123  
 26124  					console.warn( "THREE.ShapeUtils: Duplicate point", key, i );
 26125  
 26126  				}
 26127  
 26128  				allPointsMap[ key ] = i;
 26129  
 26130  			}
 26131  
 26132  			// remove holes by cutting paths to holes and adding them to the shape
 26133  			var shapeWithoutHoles = removeHoles( contour, holes );
 26134  
 26135  			var triangles = ShapeUtils.triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape
 26136  			//console.log( "triangles",triangles, triangles.length );
 26137  
 26138  			// check all face vertices against all points map
 26139  
 26140  			for ( i = 0, il = triangles.length; i < il; i ++ ) {
 26141  
 26142  				face = triangles[ i ];
 26143  
 26144  				for ( f = 0; f < 3; f ++ ) {
 26145  
 26146  					key = face[ f ].x + ":" + face[ f ].y;
 26147  
 26148  					index = allPointsMap[ key ];
 26149  
 26150  					if ( index !== undefined ) {
 26151  
 26152  						face[ f ] = index;
 26153  
 26154  					}
 26155  
 26156  				}
 26157  
 26158  			}
 26159  
 26160  			return triangles.concat();
 26161  
 26162  		},
 26163  
 26164  		isClockWise: function ( pts ) {
 26165  
 26166  			return ShapeUtils.area( pts ) < 0;
 26167  
 26168  		}
 26169  
 26170  	};
 26171  
 26172  	/**
 26173  	 * @author zz85 / http://www.lab4games.net/zz85/blog
 26174  	 *
 26175  	 * Creates extruded geometry from a path shape.
 26176  	 *
 26177  	 * parameters = {
 26178  	 *
 26179  	 *  curveSegments: <int>, // number of points on the curves
 26180  	 *  steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
 26181  	 *  amount: <int>, // Depth to extrude the shape
 26182  	 *
 26183  	 *  bevelEnabled: <bool>, // turn on bevel
 26184  	 *  bevelThickness: <float>, // how deep into the original shape bevel goes
 26185  	 *  bevelSize: <float>, // how far from shape outline is bevel
 26186  	 *  bevelSegments: <int>, // number of bevel layers
 26187  	 *
 26188  	 *  extrudePath: <THREE.Curve> // curve to extrude shape along
 26189  	 *  frames: <Object> // containing arrays of tangents, normals, binormals
 26190  	 *
 26191  	 *  uvGenerator: <Object> // object that provides UV generator functions
 26192  	 *
 26193  	 * }
 26194  	 **/
 26195  
 26196  	function ExtrudeGeometry( shapes, options ) {
 26197  
 26198  		if ( typeof( shapes ) === "undefined" ) {
 26199  
 26200  			shapes = [];
 26201  			return;
 26202  
 26203  		}
 26204  
 26205  		Geometry.call( this );
 26206  
 26207  		this.type = 'ExtrudeGeometry';
 26208  
 26209  		shapes = Array.isArray( shapes ) ? shapes : [ shapes ];
 26210  
 26211  		this.addShapeList( shapes, options );
 26212  
 26213  		this.computeFaceNormals();
 26214  
 26215  		// can't really use automatic vertex normals
 26216  		// as then front and back sides get smoothed too
 26217  		// should do separate smoothing just for sides
 26218  
 26219  		//this.computeVertexNormals();
 26220  
 26221  		//console.log( "took", ( Date.now() - startTime ) );
 26222  
 26223  	}
 26224  
 26225  	ExtrudeGeometry.prototype = Object.create( Geometry.prototype );
 26226  	ExtrudeGeometry.prototype.constructor = ExtrudeGeometry;
 26227  
 26228  	ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) {
 26229  
 26230  		var sl = shapes.length;
 26231  
 26232  		for ( var s = 0; s < sl; s ++ ) {
 26233  
 26234  			var shape = shapes[ s ];
 26235  			this.addShape( shape, options );
 26236  
 26237  		}
 26238  
 26239  	};
 26240  
 26241  	ExtrudeGeometry.prototype.addShape = function ( shape, options ) {
 26242  
 26243  		var amount = options.amount !== undefined ? options.amount : 100;
 26244  
 26245  		var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10
 26246  		var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8
 26247  		var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
 26248  
 26249  		var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false
 26250  
 26251  		var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
 26252  
 26253  		var steps = options.steps !== undefined ? options.steps : 1;
 26254  
 26255  		var extrudePath = options.extrudePath;
 26256  		var extrudePts, extrudeByPath = false;
 26257  
 26258  		// Use default WorldUVGenerator if no UV generators are specified.
 26259  		var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : ExtrudeGeometry.WorldUVGenerator;
 26260  
 26261  		var splineTube, binormal, normal, position2;
 26262  		if ( extrudePath ) {
 26263  
 26264  			extrudePts = extrudePath.getSpacedPoints( steps );
 26265  
 26266  			extrudeByPath = true;
 26267  			bevelEnabled = false; // bevels not supported for path extrusion
 26268  
 26269  			// SETUP TNB variables
 26270  
 26271  			// TODO1 - have a .isClosed in spline?
 26272  
 26273  			splineTube = options.frames !== undefined ? options.frames : extrudePath.computeFrenetFrames( steps, false );
 26274  
 26275  			// console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
 26276  
 26277  			binormal = new Vector3();
 26278  			normal = new Vector3();
 26279  			position2 = new Vector3();
 26280  
 26281  		}
 26282  
 26283  		// Safeguards if bevels are not enabled
 26284  
 26285  		if ( ! bevelEnabled ) {
 26286  
 26287  			bevelSegments = 0;
 26288  			bevelThickness = 0;
 26289  			bevelSize = 0;
 26290  
 26291  		}
 26292  
 26293  		// Variables initialization
 26294  
 26295  		var ahole, h, hl; // looping of holes
 26296  		var scope = this;
 26297  
 26298  		var shapesOffset = this.vertices.length;
 26299  
 26300  		var shapePoints = shape.extractPoints( curveSegments );
 26301  
 26302  		var vertices = shapePoints.shape;
 26303  		var holes = shapePoints.holes;
 26304  
 26305  		var reverse = ! ShapeUtils.isClockWise( vertices );
 26306  
 26307  		if ( reverse ) {
 26308  
 26309  			vertices = vertices.reverse();
 26310  
 26311  			// Maybe we should also check if holes are in the opposite direction, just to be safe ...
 26312  
 26313  			for ( h = 0, hl = holes.length; h < hl; h ++ ) {
 26314  
 26315  				ahole = holes[ h ];
 26316  
 26317  				if ( ShapeUtils.isClockWise( ahole ) ) {
 26318  
 26319  					holes[ h ] = ahole.reverse();
 26320  
 26321  				}
 26322  
 26323  			}
 26324  
 26325  			reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)!
 26326  
 26327  		}
 26328  
 26329  
 26330  		var faces = ShapeUtils.triangulateShape( vertices, holes );
 26331  
 26332  		/* Vertices */
 26333  
 26334  		var contour = vertices; // vertices has all points but contour has only points of circumference
 26335  
 26336  		for ( h = 0, hl = holes.length; h < hl; h ++ ) {
 26337  
 26338  			ahole = holes[ h ];
 26339  
 26340  			vertices = vertices.concat( ahole );
 26341  
 26342  		}
 26343  
 26344  
 26345  		function scalePt2( pt, vec, size ) {
 26346  
 26347  			if ( ! vec ) console.error( "THREE.ExtrudeGeometry: vec does not exist" );
 26348  
 26349  			return vec.clone().multiplyScalar( size ).add( pt );
 26350  
 26351  		}
 26352  
 26353  		var b, bs, t, z,
 26354  			vert, vlen = vertices.length,
 26355  			face, flen = faces.length;
 26356  
 26357  
 26358  		// Find directions for point movement
 26359  
 26360  
 26361  		function getBevelVec( inPt, inPrev, inNext ) {
 26362  
 26363  			// computes for inPt the corresponding point inPt' on a new contour
 26364  			//   shifted by 1 unit (length of normalized vector) to the left
 26365  			// if we walk along contour clockwise, this new contour is outside the old one
 26366  			//
 26367  			// inPt' is the intersection of the two lines parallel to the two
 26368  			//  adjacent edges of inPt at a distance of 1 unit on the left side.
 26369  
 26370  			var v_trans_x, v_trans_y, shrink_by = 1;		// resulting translation vector for inPt
 26371  
 26372  			// good reading for geometry algorithms (here: line-line intersection)
 26373  			// http://geomalgorithms.com/a05-_intersect-1.html
 26374  
 26375  			var v_prev_x = inPt.x - inPrev.x, v_prev_y = inPt.y - inPrev.y;
 26376  			var v_next_x = inNext.x - inPt.x, v_next_y = inNext.y - inPt.y;
 26377  
 26378  			var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );
 26379  
 26380  			// check for collinear edges
 26381  			var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
 26382  
 26383  			if ( Math.abs( collinear0 ) > Number.EPSILON ) {
 26384  
 26385  				// not collinear
 26386  
 26387  				// length of vectors for normalizing
 26388  
 26389  				var v_prev_len = Math.sqrt( v_prev_lensq );
 26390  				var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
 26391  
 26392  				// shift adjacent points by unit vectors to the left
 26393  
 26394  				var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
 26395  				var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
 26396  
 26397  				var ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
 26398  				var ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
 26399  
 26400  				// scaling factor for v_prev to intersection point
 26401  
 26402  				var sf = (  ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
 26403  							( ptNextShift_y - ptPrevShift_y ) * v_next_x    ) /
 26404  						  ( v_prev_x * v_next_y - v_prev_y * v_next_x );
 26405  
 26406  				// vector from inPt to intersection point
 26407  
 26408  				v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
 26409  				v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
 26410  
 26411  				// Don't normalize!, otherwise sharp corners become ugly
 26412  				//  but prevent crazy spikes
 26413  				var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );
 26414  				if ( v_trans_lensq <= 2 ) {
 26415  
 26416  					return	new Vector2( v_trans_x, v_trans_y );
 26417  
 26418  				} else {
 26419  
 26420  					shrink_by = Math.sqrt( v_trans_lensq / 2 );
 26421  
 26422  				}
 26423  
 26424  			} else {
 26425  
 26426  				// handle special case of collinear edges
 26427  
 26428  				var direction_eq = false;		// assumes: opposite
 26429  				if ( v_prev_x > Number.EPSILON ) {
 26430  
 26431  					if ( v_next_x > Number.EPSILON ) {
 26432  
 26433  						direction_eq = true;
 26434  
 26435  					}
 26436  
 26437  				} else {
 26438  
 26439  					if ( v_prev_x < - Number.EPSILON ) {
 26440  
 26441  						if ( v_next_x < - Number.EPSILON ) {
 26442  
 26443  							direction_eq = true;
 26444  
 26445  						}
 26446  
 26447  					} else {
 26448  
 26449  						if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {
 26450  
 26451  							direction_eq = true;
 26452  
 26453  						}
 26454  
 26455  					}
 26456  
 26457  				}
 26458  
 26459  				if ( direction_eq ) {
 26460  
 26461  					// console.log("Warning: lines are a straight sequence");
 26462  					v_trans_x = - v_prev_y;
 26463  					v_trans_y =  v_prev_x;
 26464  					shrink_by = Math.sqrt( v_prev_lensq );
 26465  
 26466  				} else {
 26467  
 26468  					// console.log("Warning: lines are a straight spike");
 26469  					v_trans_x = v_prev_x;
 26470  					v_trans_y = v_prev_y;
 26471  					shrink_by = Math.sqrt( v_prev_lensq / 2 );
 26472  
 26473  				}
 26474  
 26475  			}
 26476  
 26477  			return	new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );
 26478  
 26479  		}
 26480  
 26481  
 26482  		var contourMovements = [];
 26483  
 26484  		for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
 26485  
 26486  			if ( j === il ) j = 0;
 26487  			if ( k === il ) k = 0;
 26488  
 26489  			//  (j)---(i)---(k)
 26490  			// console.log('i,j,k', i, j , k)
 26491  
 26492  			contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
 26493  
 26494  		}
 26495  
 26496  		var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat();
 26497  
 26498  		for ( h = 0, hl = holes.length; h < hl; h ++ ) {
 26499  
 26500  			ahole = holes[ h ];
 26501  
 26502  			oneHoleMovements = [];
 26503  
 26504  			for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
 26505  
 26506  				if ( j === il ) j = 0;
 26507  				if ( k === il ) k = 0;
 26508  
 26509  				//  (j)---(i)---(k)
 26510  				oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
 26511  
 26512  			}
 26513  
 26514  			holesMovements.push( oneHoleMovements );
 26515  			verticesMovements = verticesMovements.concat( oneHoleMovements );
 26516  
 26517  		}
 26518  
 26519  
 26520  		// Loop bevelSegments, 1 for the front, 1 for the back
 26521  
 26522  		for ( b = 0; b < bevelSegments; b ++ ) {
 26523  
 26524  			//for ( b = bevelSegments; b > 0; b -- ) {
 26525  
 26526  			t = b / bevelSegments;
 26527  			z = bevelThickness * Math.cos( t * Math.PI / 2 );
 26528  			bs = bevelSize * Math.sin( t * Math.PI / 2 );
 26529  
 26530  			// contract shape
 26531  
 26532  			for ( i = 0, il = contour.length; i < il; i ++ ) {
 26533  
 26534  				vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
 26535  
 26536  				v( vert.x, vert.y,  - z );
 26537  
 26538  			}
 26539  
 26540  			// expand holes
 26541  
 26542  			for ( h = 0, hl = holes.length; h < hl; h ++ ) {
 26543  
 26544  				ahole = holes[ h ];
 26545  				oneHoleMovements = holesMovements[ h ];
 26546  
 26547  				for ( i = 0, il = ahole.length; i < il; i ++ ) {
 26548  
 26549  					vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
 26550  
 26551  					v( vert.x, vert.y,  - z );
 26552  
 26553  				}
 26554  
 26555  			}
 26556  
 26557  		}
 26558  
 26559  		bs = bevelSize;
 26560  
 26561  		// Back facing vertices
 26562  
 26563  		for ( i = 0; i < vlen; i ++ ) {
 26564  
 26565  			vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
 26566  
 26567  			if ( ! extrudeByPath ) {
 26568  
 26569  				v( vert.x, vert.y, 0 );
 26570  
 26571  			} else {
 26572  
 26573  				// v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
 26574  
 26575  				normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );
 26576  				binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );
 26577  
 26578  				position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );
 26579  
 26580  				v( position2.x, position2.y, position2.z );
 26581  
 26582  			}
 26583  
 26584  		}
 26585  
 26586  		// Add stepped vertices...
 26587  		// Including front facing vertices
 26588  
 26589  		var s;
 26590  
 26591  		for ( s = 1; s <= steps; s ++ ) {
 26592  
 26593  			for ( i = 0; i < vlen; i ++ ) {
 26594  
 26595  				vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
 26596  
 26597  				if ( ! extrudeByPath ) {
 26598  
 26599  					v( vert.x, vert.y, amount / steps * s );
 26600  
 26601  				} else {
 26602  
 26603  					// v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
 26604  
 26605  					normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );
 26606  					binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );
 26607  
 26608  					position2.copy( extrudePts[ s ] ).add( normal ).add( binormal );
 26609  
 26610  					v( position2.x, position2.y, position2.z );
 26611  
 26612  				}
 26613  
 26614  			}
 26615  
 26616  		}
 26617  
 26618  
 26619  		// Add bevel segments planes
 26620  
 26621  		//for ( b = 1; b <= bevelSegments; b ++ ) {
 26622  		for ( b = bevelSegments - 1; b >= 0; b -- ) {
 26623  
 26624  			t = b / bevelSegments;
 26625  			z = bevelThickness * Math.cos ( t * Math.PI / 2 );
 26626  			bs = bevelSize * Math.sin( t * Math.PI / 2 );
 26627  
 26628  			// contract shape
 26629  
 26630  			for ( i = 0, il = contour.length; i < il; i ++ ) {
 26631  
 26632  				vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
 26633  				v( vert.x, vert.y,  amount + z );
 26634  
 26635  			}
 26636  
 26637  			// expand holes
 26638  
 26639  			for ( h = 0, hl = holes.length; h < hl; h ++ ) {
 26640  
 26641  				ahole = holes[ h ];
 26642  				oneHoleMovements = holesMovements[ h ];
 26643  
 26644  				for ( i = 0, il = ahole.length; i < il; i ++ ) {
 26645  
 26646  					vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
 26647  
 26648  					if ( ! extrudeByPath ) {
 26649  
 26650  						v( vert.x, vert.y,  amount + z );
 26651  
 26652  					} else {
 26653  
 26654  						v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
 26655  
 26656  					}
 26657  
 26658  				}
 26659  
 26660  			}
 26661  
 26662  		}
 26663  
 26664  		/* Faces */
 26665  
 26666  		// Top and bottom faces
 26667  
 26668  		buildLidFaces();
 26669  
 26670  		// Sides faces
 26671  
 26672  		buildSideFaces();
 26673  
 26674  
 26675  		/////  Internal functions
 26676  
 26677  		function buildLidFaces() {
 26678  
 26679  			if ( bevelEnabled ) {
 26680  
 26681  				var layer = 0; // steps + 1
 26682  				var offset = vlen * layer;
 26683  
 26684  				// Bottom faces
 26685  
 26686  				for ( i = 0; i < flen; i ++ ) {
 26687  
 26688  					face = faces[ i ];
 26689  					f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );
 26690  
 26691  				}
 26692  
 26693  				layer = steps + bevelSegments * 2;
 26694  				offset = vlen * layer;
 26695  
 26696  				// Top faces
 26697  
 26698  				for ( i = 0; i < flen; i ++ ) {
 26699  
 26700  					face = faces[ i ];
 26701  					f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );
 26702  
 26703  				}
 26704  
 26705  			} else {
 26706  
 26707  				// Bottom faces
 26708  
 26709  				for ( i = 0; i < flen; i ++ ) {
 26710  
 26711  					face = faces[ i ];
 26712  					f3( face[ 2 ], face[ 1 ], face[ 0 ] );
 26713  
 26714  				}
 26715  
 26716  				// Top faces
 26717  
 26718  				for ( i = 0; i < flen; i ++ ) {
 26719  
 26720  					face = faces[ i ];
 26721  					f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );
 26722  
 26723  				}
 26724  
 26725  			}
 26726  
 26727  		}
 26728  
 26729  		// Create faces for the z-sides of the shape
 26730  
 26731  		function buildSideFaces() {
 26732  
 26733  			var layeroffset = 0;
 26734  			sidewalls( contour, layeroffset );
 26735  			layeroffset += contour.length;
 26736  
 26737  			for ( h = 0, hl = holes.length; h < hl; h ++ ) {
 26738  
 26739  				ahole = holes[ h ];
 26740  				sidewalls( ahole, layeroffset );
 26741  
 26742  				//, true
 26743  				layeroffset += ahole.length;
 26744  
 26745  			}
 26746  
 26747  		}
 26748  
 26749  		function sidewalls( contour, layeroffset ) {
 26750  
 26751  			var j, k;
 26752  			i = contour.length;
 26753  
 26754  			while ( -- i >= 0 ) {
 26755  
 26756  				j = i;
 26757  				k = i - 1;
 26758  				if ( k < 0 ) k = contour.length - 1;
 26759  
 26760  				//console.log('b', i,j, i-1, k,vertices.length);
 26761  
 26762  				var s = 0, sl = steps  + bevelSegments * 2;
 26763  
 26764  				for ( s = 0; s < sl; s ++ ) {
 26765  
 26766  					var slen1 = vlen * s;
 26767  					var slen2 = vlen * ( s + 1 );
 26768  
 26769  					var a = layeroffset + j + slen1,
 26770  						b = layeroffset + k + slen1,
 26771  						c = layeroffset + k + slen2,
 26772  						d = layeroffset + j + slen2;
 26773  
 26774  					f4( a, b, c, d, contour, s, sl, j, k );
 26775  
 26776  				}
 26777  
 26778  			}
 26779  
 26780  		}
 26781  
 26782  
 26783  		function v( x, y, z ) {
 26784  
 26785  			scope.vertices.push( new Vector3( x, y, z ) );
 26786  
 26787  		}
 26788  
 26789  		function f3( a, b, c ) {
 26790  
 26791  			a += shapesOffset;
 26792  			b += shapesOffset;
 26793  			c += shapesOffset;
 26794  
 26795  			scope.faces.push( new Face3( a, b, c, null, null, 0 ) );
 26796  
 26797  			var uvs = uvgen.generateTopUV( scope, a, b, c );
 26798  
 26799  			scope.faceVertexUvs[ 0 ].push( uvs );
 26800  
 26801  		}
 26802  
 26803  		function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) {
 26804  
 26805  			a += shapesOffset;
 26806  			b += shapesOffset;
 26807  			c += shapesOffset;
 26808  			d += shapesOffset;
 26809  
 26810  			scope.faces.push( new Face3( a, b, d, null, null, 1 ) );
 26811  			scope.faces.push( new Face3( b, c, d, null, null, 1 ) );
 26812  
 26813  			var uvs = uvgen.generateSideWallUV( scope, a, b, c, d );
 26814  
 26815  			scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] );
 26816  			scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] );
 26817  
 26818  		}
 26819  
 26820  	};
 26821  
 26822  	ExtrudeGeometry.WorldUVGenerator = {
 26823  
 26824  		generateTopUV: function ( geometry, indexA, indexB, indexC ) {
 26825  
 26826  			var vertices = geometry.vertices;
 26827  
 26828  			var a = vertices[ indexA ];
 26829  			var b = vertices[ indexB ];
 26830  			var c = vertices[ indexC ];
 26831  
 26832  			return [
 26833  				new Vector2( a.x, a.y ),
 26834  				new Vector2( b.x, b.y ),
 26835  				new Vector2( c.x, c.y )
 26836  			];
 26837  
 26838  		},
 26839  
 26840  		generateSideWallUV: function ( geometry, indexA, indexB, indexC, indexD ) {
 26841  
 26842  			var vertices = geometry.vertices;
 26843  
 26844  			var a = vertices[ indexA ];
 26845  			var b = vertices[ indexB ];
 26846  			var c = vertices[ indexC ];
 26847  			var d = vertices[ indexD ];
 26848  
 26849  			if ( Math.abs( a.y - b.y ) < 0.01 ) {
 26850  
 26851  				return [
 26852  					new Vector2( a.x, 1 - a.z ),
 26853  					new Vector2( b.x, 1 - b.z ),
 26854  					new Vector2( c.x, 1 - c.z ),
 26855  					new Vector2( d.x, 1 - d.z )
 26856  				];
 26857  
 26858  			} else {
 26859  
 26860  				return [
 26861  					new Vector2( a.y, 1 - a.z ),
 26862  					new Vector2( b.y, 1 - b.z ),
 26863  					new Vector2( c.y, 1 - c.z ),
 26864  					new Vector2( d.y, 1 - d.z )
 26865  				];
 26866  
 26867  			}
 26868  
 26869  		}
 26870  	};
 26871  
 26872  	/**
 26873  	 * @author zz85 / http://www.lab4games.net/zz85/blog
 26874  	 * @author alteredq / http://alteredqualia.com/
 26875  	 *
 26876  	 * Text = 3D Text
 26877  	 *
 26878  	 * parameters = {
 26879  	 *  font: <THREE.Font>, // font
 26880  	 *
 26881  	 *  size: <float>, // size of the text
 26882  	 *  height: <float>, // thickness to extrude text
 26883  	 *  curveSegments: <int>, // number of points on the curves
 26884  	 *
 26885  	 *  bevelEnabled: <bool>, // turn on bevel
 26886  	 *  bevelThickness: <float>, // how deep into text bevel goes
 26887  	 *  bevelSize: <float> // how far from text outline is bevel
 26888  	 * }
 26889  	 */
 26890  
 26891  	function TextGeometry( text, parameters ) {
 26892  
 26893  		parameters = parameters || {};
 26894  
 26895  		var font = parameters.font;
 26896  
 26897  		if ( ( font && font.isFont ) === false ) {
 26898  
 26899  			console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' );
 26900  			return new Geometry();
 26901  
 26902  		}
 26903  
 26904  		var shapes = font.generateShapes( text, parameters.size, parameters.curveSegments );
 26905  
 26906  		// translate parameters to ExtrudeGeometry API
 26907  
 26908  		parameters.amount = parameters.height !== undefined ? parameters.height : 50;
 26909  
 26910  		// defaults
 26911  
 26912  		if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
 26913  		if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
 26914  		if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
 26915  
 26916  		ExtrudeGeometry.call( this, shapes, parameters );
 26917  
 26918  		this.type = 'TextGeometry';
 26919  
 26920  	}
 26921  
 26922  	TextGeometry.prototype = Object.create( ExtrudeGeometry.prototype );
 26923  	TextGeometry.prototype.constructor = TextGeometry;
 26924  
 26925  	/**
 26926  	 * @author mrdoob / http://mrdoob.com/
 26927  	 */
 26928  
 26929  	function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
 26930  
 26931  		Geometry.call( this );
 26932  
 26933  		this.type = 'SphereGeometry';
 26934  
 26935  		this.parameters = {
 26936  			radius: radius,
 26937  			widthSegments: widthSegments,
 26938  			heightSegments: heightSegments,
 26939  			phiStart: phiStart,
 26940  			phiLength: phiLength,
 26941  			thetaStart: thetaStart,
 26942  			thetaLength: thetaLength
 26943  		};
 26944  
 26945  		this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) );
 26946  
 26947  	}
 26948  
 26949  	SphereGeometry.prototype = Object.create( Geometry.prototype );
 26950  	SphereGeometry.prototype.constructor = SphereGeometry;
 26951  
 26952  	/**
 26953  	 * @author benaadams / https://twitter.com/ben_a_adams
 26954  	 * @author Mugen87 / https://github.com/Mugen87
 26955  	 */
 26956  
 26957  	function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
 26958  
 26959  		BufferGeometry.call( this );
 26960  
 26961  		this.type = 'SphereBufferGeometry';
 26962  
 26963  		this.parameters = {
 26964  			radius: radius,
 26965  			widthSegments: widthSegments,
 26966  			heightSegments: heightSegments,
 26967  			phiStart: phiStart,
 26968  			phiLength: phiLength,
 26969  			thetaStart: thetaStart,
 26970  			thetaLength: thetaLength
 26971  		};
 26972  
 26973  		radius = radius || 50;
 26974  
 26975  		widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );
 26976  		heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );
 26977  
 26978  		phiStart = phiStart !== undefined ? phiStart : 0;
 26979  		phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;
 26980  
 26981  		thetaStart = thetaStart !== undefined ? thetaStart : 0;
 26982  		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;
 26983  
 26984  		var thetaEnd = thetaStart + thetaLength;
 26985  
 26986  		var ix, iy;
 26987  
 26988  		var index = 0;
 26989  		var grid = [];
 26990  
 26991  		var vertex = new Vector3();
 26992  		var normal = new Vector3();
 26993  
 26994  		// buffers
 26995  
 26996  		var indices = [];
 26997  		var vertices = [];
 26998  		var normals = [];
 26999  		var uvs = [];
 27000  
 27001  		// generate vertices, normals and uvs
 27002  
 27003  		for ( iy = 0; iy <= heightSegments; iy ++ ) {
 27004  
 27005  			var verticesRow = [];
 27006  
 27007  			var v = iy / heightSegments;
 27008  
 27009  			for ( ix = 0; ix <= widthSegments; ix ++ ) {
 27010  
 27011  				var u = ix / widthSegments;
 27012  
 27013  				// vertex
 27014  
 27015  				vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
 27016  				vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
 27017  				vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
 27018  
 27019  				vertices.push( vertex.x, vertex.y, vertex.z );
 27020  
 27021  				// normal
 27022  
 27023  				normal.set( vertex.x, vertex.y, vertex.z ).normalize();
 27024  				normals.push( normal.x, normal.y, normal.z );
 27025  
 27026  				// uv
 27027  
 27028  				uvs.push( u, 1 - v );
 27029  
 27030  				verticesRow.push( index ++ );
 27031  
 27032  			}
 27033  
 27034  			grid.push( verticesRow );
 27035  
 27036  		}
 27037  
 27038  		// indices
 27039  
 27040  		for ( iy = 0; iy < heightSegments; iy ++ ) {
 27041  
 27042  			for ( ix = 0; ix < widthSegments; ix ++ ) {
 27043  
 27044  				var a = grid[ iy ][ ix + 1 ];
 27045  				var b = grid[ iy ][ ix ];
 27046  				var c = grid[ iy + 1 ][ ix ];
 27047  				var d = grid[ iy + 1 ][ ix + 1 ];
 27048  
 27049  				if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
 27050  				if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
 27051  
 27052  			}
 27053  
 27054  		}
 27055  
 27056  		// build geometry
 27057  
 27058  		this.setIndex( indices );
 27059  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 27060  		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
 27061  		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 27062  
 27063  	}
 27064  
 27065  	SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 27066  	SphereBufferGeometry.prototype.constructor = SphereBufferGeometry;
 27067  
 27068  	/**
 27069  	 * @author Kaleb Murphy
 27070  	 */
 27071  
 27072  	function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
 27073  
 27074  		Geometry.call( this );
 27075  
 27076  		this.type = 'RingGeometry';
 27077  
 27078  		this.parameters = {
 27079  			innerRadius: innerRadius,
 27080  			outerRadius: outerRadius,
 27081  			thetaSegments: thetaSegments,
 27082  			phiSegments: phiSegments,
 27083  			thetaStart: thetaStart,
 27084  			thetaLength: thetaLength
 27085  		};
 27086  
 27087  		this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) );
 27088  
 27089  	}
 27090  
 27091  	RingGeometry.prototype = Object.create( Geometry.prototype );
 27092  	RingGeometry.prototype.constructor = RingGeometry;
 27093  
 27094  	/**
 27095  	 * @author Mugen87 / https://github.com/Mugen87
 27096  	 */
 27097  
 27098  	function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
 27099  
 27100  		BufferGeometry.call( this );
 27101  
 27102  		this.type = 'RingBufferGeometry';
 27103  
 27104  		this.parameters = {
 27105  			innerRadius: innerRadius,
 27106  			outerRadius: outerRadius,
 27107  			thetaSegments: thetaSegments,
 27108  			phiSegments: phiSegments,
 27109  			thetaStart: thetaStart,
 27110  			thetaLength: thetaLength
 27111  		};
 27112  
 27113  		innerRadius = innerRadius || 20;
 27114  		outerRadius = outerRadius || 50;
 27115  
 27116  		thetaStart = thetaStart !== undefined ? thetaStart : 0;
 27117  		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
 27118  
 27119  		thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8;
 27120  		phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1;
 27121  
 27122  		// buffers
 27123  
 27124  		var indices = [];
 27125  		var vertices = [];
 27126  		var normals = [];
 27127  		var uvs = [];
 27128  
 27129  		// some helper variables
 27130  
 27131  		var segment;
 27132  		var radius = innerRadius;
 27133  		var radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
 27134  		var vertex = new Vector3();
 27135  		var uv = new Vector2();
 27136  		var j, i;
 27137  
 27138  		// generate vertices, normals and uvs
 27139  
 27140  		for ( j = 0; j <= phiSegments; j ++ ) {
 27141  
 27142  			for ( i = 0; i <= thetaSegments; i ++ ) {
 27143  
 27144  				// values are generate from the inside of the ring to the outside
 27145  
 27146  				segment = thetaStart + i / thetaSegments * thetaLength;
 27147  
 27148  				// vertex
 27149  
 27150  				vertex.x = radius * Math.cos( segment );
 27151  				vertex.y = radius * Math.sin( segment );
 27152  
 27153  				vertices.push( vertex.x, vertex.y, vertex.z );
 27154  
 27155  				// normal
 27156  
 27157  				normals.push( 0, 0, 1 );
 27158  
 27159  				// uv
 27160  
 27161  				uv.x = ( vertex.x / outerRadius + 1 ) / 2;
 27162  				uv.y = ( vertex.y / outerRadius + 1 ) / 2;
 27163  
 27164  				uvs.push( uv.x, uv.y );
 27165  
 27166  			}
 27167  
 27168  			// increase the radius for next row of vertices
 27169  
 27170  			radius += radiusStep;
 27171  
 27172  		}
 27173  
 27174  		// indices
 27175  
 27176  		for ( j = 0; j < phiSegments; j ++ ) {
 27177  
 27178  			var thetaSegmentLevel = j * ( thetaSegments + 1 );
 27179  
 27180  			for ( i = 0; i < thetaSegments; i ++ ) {
 27181  
 27182  				segment = i + thetaSegmentLevel;
 27183  
 27184  				var a = segment;
 27185  				var b = segment + thetaSegments + 1;
 27186  				var c = segment + thetaSegments + 2;
 27187  				var d = segment + 1;
 27188  
 27189  				// faces
 27190  
 27191  				indices.push( a, b, d );
 27192  				indices.push( b, c, d );
 27193  
 27194  			}
 27195  
 27196  		}
 27197  
 27198  		// build geometry
 27199  
 27200  		this.setIndex( indices );
 27201  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 27202  		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
 27203  		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 27204  
 27205  	}
 27206  
 27207  	RingBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 27208  	RingBufferGeometry.prototype.constructor = RingBufferGeometry;
 27209  
 27210  	/**
 27211  	 * @author astrodud / http://astrodud.isgreat.org/
 27212  	 * @author zz85 / https://github.com/zz85
 27213  	 * @author bhouston / http://clara.io
 27214  	 */
 27215  
 27216  	// points - to create a closed torus, one must use a set of points
 27217  	//    like so: [ a, b, c, d, a ], see first is the same as last.
 27218  	// segments - the number of circumference segments to create
 27219  	// phiStart - the starting radian
 27220  	// phiLength - the radian (0 to 2PI) range of the lathed section
 27221  	//    2PI is a closed lathe, less than 2PI is a portion.
 27222  
 27223  	function LatheGeometry( points, segments, phiStart, phiLength ) {
 27224  
 27225  		Geometry.call( this );
 27226  
 27227  		this.type = 'LatheGeometry';
 27228  
 27229  		this.parameters = {
 27230  			points: points,
 27231  			segments: segments,
 27232  			phiStart: phiStart,
 27233  			phiLength: phiLength
 27234  		};
 27235  
 27236  		this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) );
 27237  		this.mergeVertices();
 27238  
 27239  	}
 27240  
 27241  	LatheGeometry.prototype = Object.create( Geometry.prototype );
 27242  	LatheGeometry.prototype.constructor = LatheGeometry;
 27243  
 27244  	/**
 27245  	 * @author Mugen87 / https://github.com/Mugen87
 27246  	 */
 27247  
 27248  	function LatheBufferGeometry( points, segments, phiStart, phiLength ) {
 27249  
 27250  		BufferGeometry.call( this );
 27251  
 27252  		this.type = 'LatheBufferGeometry';
 27253  
 27254  		this.parameters = {
 27255  			points: points,
 27256  			segments: segments,
 27257  			phiStart: phiStart,
 27258  			phiLength: phiLength
 27259  		};
 27260  
 27261  		segments = Math.floor( segments ) || 12;
 27262  		phiStart = phiStart || 0;
 27263  		phiLength = phiLength || Math.PI * 2;
 27264  
 27265  		// clamp phiLength so it's in range of [ 0, 2PI ]
 27266  
 27267  		phiLength = _Math.clamp( phiLength, 0, Math.PI * 2 );
 27268  
 27269  
 27270  		// buffers
 27271  
 27272  		var indices = [];
 27273  		var vertices = [];
 27274  		var uvs = [];
 27275  
 27276  		// helper variables
 27277  
 27278  		var base;
 27279  		var inverseSegments = 1.0 / segments;
 27280  		var vertex = new Vector3();
 27281  		var uv = new Vector2();
 27282  		var i, j;
 27283  
 27284  		// generate vertices and uvs
 27285  
 27286  		for ( i = 0; i <= segments; i ++ ) {
 27287  
 27288  			var phi = phiStart + i * inverseSegments * phiLength;
 27289  
 27290  			var sin = Math.sin( phi );
 27291  			var cos = Math.cos( phi );
 27292  
 27293  			for ( j = 0; j <= ( points.length - 1 ); j ++ ) {
 27294  
 27295  				// vertex
 27296  
 27297  				vertex.x = points[ j ].x * sin;
 27298  				vertex.y = points[ j ].y;
 27299  				vertex.z = points[ j ].x * cos;
 27300  
 27301  				vertices.push( vertex.x, vertex.y, vertex.z );
 27302  
 27303  				// uv
 27304  
 27305  				uv.x = i / segments;
 27306  				uv.y = j / ( points.length - 1 );
 27307  
 27308  				uvs.push( uv.x, uv.y );
 27309  
 27310  
 27311  			}
 27312  
 27313  		}
 27314  
 27315  		// indices
 27316  
 27317  		for ( i = 0; i < segments; i ++ ) {
 27318  
 27319  			for ( j = 0; j < ( points.length - 1 ); j ++ ) {
 27320  
 27321  				base = j + i * points.length;
 27322  
 27323  				var a = base;
 27324  				var b = base + points.length;
 27325  				var c = base + points.length + 1;
 27326  				var d = base + 1;
 27327  
 27328  				// faces
 27329  
 27330  				indices.push( a, b, d );
 27331  				indices.push( b, c, d );
 27332  
 27333  			}
 27334  
 27335  		}
 27336  
 27337  		// build geometry
 27338  
 27339  		this.setIndex( indices );
 27340  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 27341  		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 27342  
 27343  		// generate normals
 27344  
 27345  		this.computeVertexNormals();
 27346  
 27347  		// if the geometry is closed, we need to average the normals along the seam.
 27348  		// because the corresponding vertices are identical (but still have different UVs).
 27349  
 27350  		if ( phiLength === Math.PI * 2 ) {
 27351  
 27352  			var normals = this.attributes.normal.array;
 27353  			var n1 = new Vector3();
 27354  			var n2 = new Vector3();
 27355  			var n = new Vector3();
 27356  
 27357  			// this is the buffer offset for the last line of vertices
 27358  
 27359  			base = segments * points.length * 3;
 27360  
 27361  			for ( i = 0, j = 0; i < points.length; i ++, j += 3 ) {
 27362  
 27363  				// select the normal of the vertex in the first line
 27364  
 27365  				n1.x = normals[ j + 0 ];
 27366  				n1.y = normals[ j + 1 ];
 27367  				n1.z = normals[ j + 2 ];
 27368  
 27369  				// select the normal of the vertex in the last line
 27370  
 27371  				n2.x = normals[ base + j + 0 ];
 27372  				n2.y = normals[ base + j + 1 ];
 27373  				n2.z = normals[ base + j + 2 ];
 27374  
 27375  				// average normals
 27376  
 27377  				n.addVectors( n1, n2 ).normalize();
 27378  
 27379  				// assign the new values to both normals
 27380  
 27381  				normals[ j + 0 ] = normals[ base + j + 0 ] = n.x;
 27382  				normals[ j + 1 ] = normals[ base + j + 1 ] = n.y;
 27383  				normals[ j + 2 ] = normals[ base + j + 2 ] = n.z;
 27384  
 27385  			}
 27386  
 27387  		}
 27388  
 27389  	}
 27390  
 27391  	LatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 27392  	LatheBufferGeometry.prototype.constructor = LatheBufferGeometry;
 27393  
 27394  	/**
 27395  	 * @author jonobr1 / http://jonobr1.com
 27396  	 */
 27397  
 27398  	function ShapeGeometry( shapes, curveSegments ) {
 27399  
 27400  		Geometry.call( this );
 27401  
 27402  		this.type = 'ShapeGeometry';
 27403  
 27404  		if ( typeof curveSegments === 'object' ) {
 27405  
 27406  			console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' );
 27407  
 27408  			curveSegments = curveSegments.curveSegments;
 27409  
 27410  		}
 27411  
 27412  		this.parameters = {
 27413  			shapes: shapes,
 27414  			curveSegments: curveSegments
 27415  		};
 27416  
 27417  		this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) );
 27418  		this.mergeVertices();
 27419  
 27420  	}
 27421  
 27422  	ShapeGeometry.prototype = Object.create( Geometry.prototype );
 27423  	ShapeGeometry.prototype.constructor = ShapeGeometry;
 27424  
 27425  	/**
 27426  	 * @author Mugen87 / https://github.com/Mugen87
 27427  	 */
 27428  
 27429  	function ShapeBufferGeometry( shapes, curveSegments ) {
 27430  
 27431  		BufferGeometry.call( this );
 27432  
 27433  		this.type = 'ShapeBufferGeometry';
 27434  
 27435  		this.parameters = {
 27436  			shapes: shapes,
 27437  			curveSegments: curveSegments
 27438  		};
 27439  
 27440  		curveSegments = curveSegments || 12;
 27441  
 27442  		// buffers
 27443  
 27444  		var indices = [];
 27445  		var vertices = [];
 27446  		var normals = [];
 27447  		var uvs = [];
 27448  
 27449  		// helper variables
 27450  
 27451  		var groupStart = 0;
 27452  		var groupCount = 0;
 27453  
 27454  		// allow single and array values for "shapes" parameter
 27455  
 27456  		if ( Array.isArray( shapes ) === false ) {
 27457  
 27458  			addShape( shapes );
 27459  
 27460  		} else {
 27461  
 27462  			for ( var i = 0; i < shapes.length; i ++ ) {
 27463  
 27464  				addShape( shapes[ i ] );
 27465  
 27466  				this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
 27467  
 27468  				groupStart += groupCount;
 27469  				groupCount = 0;
 27470  
 27471  			}
 27472  
 27473  		}
 27474  
 27475  		// build geometry
 27476  
 27477  		this.setIndex( indices );
 27478  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 27479  		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
 27480  		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 27481  
 27482  
 27483  		// helper functions
 27484  
 27485  		function addShape( shape ) {
 27486  
 27487  			var i, l, shapeHole;
 27488  
 27489  			var indexOffset = vertices.length / 3;
 27490  			var points = shape.extractPoints( curveSegments );
 27491  
 27492  			var shapeVertices = points.shape;
 27493  			var shapeHoles = points.holes;
 27494  
 27495  			// check direction of vertices
 27496  
 27497  			if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
 27498  
 27499  				shapeVertices = shapeVertices.reverse();
 27500  
 27501  				// also check if holes are in the opposite direction
 27502  
 27503  				for ( i = 0, l = shapeHoles.length; i < l; i ++ ) {
 27504  
 27505  					shapeHole = shapeHoles[ i ];
 27506  
 27507  					if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
 27508  
 27509  						shapeHoles[ i ] = shapeHole.reverse();
 27510  
 27511  					}
 27512  
 27513  				}
 27514  
 27515  			}
 27516  
 27517  			var faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
 27518  
 27519  			// join vertices of inner and outer paths to a single array
 27520  
 27521  			for ( i = 0, l = shapeHoles.length; i < l; i ++ ) {
 27522  
 27523  				shapeHole = shapeHoles[ i ];
 27524  				shapeVertices = shapeVertices.concat( shapeHole );
 27525  
 27526  			}
 27527  
 27528  			// vertices, normals, uvs
 27529  
 27530  			for ( i = 0, l = shapeVertices.length; i < l; i ++ ) {
 27531  
 27532  				var vertex = shapeVertices[ i ];
 27533  
 27534  				vertices.push( vertex.x, vertex.y, 0 );
 27535  				normals.push( 0, 0, 1 );
 27536  				uvs.push( vertex.x, vertex.y ); // world uvs
 27537  
 27538  			}
 27539  
 27540  			// incides
 27541  
 27542  			for ( i = 0, l = faces.length; i < l; i ++ ) {
 27543  
 27544  				var face = faces[ i ];
 27545  
 27546  				var a = face[ 0 ] + indexOffset;
 27547  				var b = face[ 1 ] + indexOffset;
 27548  				var c = face[ 2 ] + indexOffset;
 27549  
 27550  				indices.push( a, b, c );
 27551  				groupCount += 3;
 27552  
 27553  			}
 27554  
 27555  		}
 27556  
 27557  	}
 27558  
 27559  	ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 27560  	ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry;
 27561  
 27562  	/**
 27563  	 * @author WestLangley / http://github.com/WestLangley
 27564  	 * @author Mugen87 / https://github.com/Mugen87
 27565  	 */
 27566  
 27567  	function EdgesGeometry( geometry, thresholdAngle ) {
 27568  
 27569  		BufferGeometry.call( this );
 27570  
 27571  		this.type = 'EdgesGeometry';
 27572  
 27573  		this.parameters = {
 27574  			thresholdAngle: thresholdAngle
 27575  		};
 27576  
 27577  		thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;
 27578  
 27579  		// buffer
 27580  
 27581  		var vertices = [];
 27582  
 27583  		// helper variables
 27584  
 27585  		var thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle );
 27586  		var edge = [ 0, 0 ], edges = {};
 27587  		var key, keys = [ 'a', 'b', 'c' ];
 27588  
 27589  		// prepare source geometry
 27590  
 27591  		var geometry2;
 27592  
 27593  		if ( geometry.isBufferGeometry ) {
 27594  
 27595  			geometry2 = new Geometry();
 27596  			geometry2.fromBufferGeometry( geometry );
 27597  
 27598  		} else {
 27599  
 27600  			geometry2 = geometry.clone();
 27601  
 27602  		}
 27603  
 27604  		geometry2.mergeVertices();
 27605  		geometry2.computeFaceNormals();
 27606  
 27607  		var sourceVertices = geometry2.vertices;
 27608  		var faces = geometry2.faces;
 27609  
 27610  		// now create a data structure where each entry represents an edge with its adjoining faces
 27611  
 27612  		for ( var i = 0, l = faces.length; i < l; i ++ ) {
 27613  
 27614  			var face = faces[ i ];
 27615  
 27616  			for ( var j = 0; j < 3; j ++ ) {
 27617  
 27618  				edge[ 0 ] = face[ keys[ j ] ];
 27619  				edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ];
 27620  				edge.sort( sortFunction );
 27621  
 27622  				key = edge.toString();
 27623  
 27624  				if ( edges[ key ] === undefined ) {
 27625  
 27626  					edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined };
 27627  
 27628  				} else {
 27629  
 27630  					edges[ key ].face2 = i;
 27631  
 27632  				}
 27633  
 27634  			}
 27635  
 27636  		}
 27637  
 27638  		// generate vertices
 27639  
 27640  		for ( key in edges ) {
 27641  
 27642  			var e = edges[ key ];
 27643  
 27644  			// an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.
 27645  
 27646  			if ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) {
 27647  
 27648  				var vertex = sourceVertices[ e.index1 ];
 27649  				vertices.push( vertex.x, vertex.y, vertex.z );
 27650  
 27651  				vertex = sourceVertices[ e.index2 ];
 27652  				vertices.push( vertex.x, vertex.y, vertex.z );
 27653  
 27654  			}
 27655  
 27656  		}
 27657  
 27658  		// build geometry
 27659  
 27660  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 27661  
 27662  		// custom array sort function
 27663  
 27664  		function sortFunction( a, b ) {
 27665  
 27666  			return a - b;
 27667  
 27668  		}
 27669  
 27670  	}
 27671  
 27672  	EdgesGeometry.prototype = Object.create( BufferGeometry.prototype );
 27673  	EdgesGeometry.prototype.constructor = EdgesGeometry;
 27674  
 27675  	/**
 27676  	 * @author mrdoob / http://mrdoob.com/
 27677  	 */
 27678  
 27679  	function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
 27680  
 27681  		Geometry.call( this );
 27682  
 27683  		this.type = 'CylinderGeometry';
 27684  
 27685  		this.parameters = {
 27686  			radiusTop: radiusTop,
 27687  			radiusBottom: radiusBottom,
 27688  			height: height,
 27689  			radialSegments: radialSegments,
 27690  			heightSegments: heightSegments,
 27691  			openEnded: openEnded,
 27692  			thetaStart: thetaStart,
 27693  			thetaLength: thetaLength
 27694  		};
 27695  
 27696  		this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) );
 27697  		this.mergeVertices();
 27698  
 27699  	}
 27700  
 27701  	CylinderGeometry.prototype = Object.create( Geometry.prototype );
 27702  	CylinderGeometry.prototype.constructor = CylinderGeometry;
 27703  
 27704  	/**
 27705  	 * @author Mugen87 / https://github.com/Mugen87
 27706  	 */
 27707  
 27708  	function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
 27709  
 27710  		BufferGeometry.call( this );
 27711  
 27712  		this.type = 'CylinderBufferGeometry';
 27713  
 27714  		this.parameters = {
 27715  			radiusTop: radiusTop,
 27716  			radiusBottom: radiusBottom,
 27717  			height: height,
 27718  			radialSegments: radialSegments,
 27719  			heightSegments: heightSegments,
 27720  			openEnded: openEnded,
 27721  			thetaStart: thetaStart,
 27722  			thetaLength: thetaLength
 27723  		};
 27724  
 27725  		var scope = this;
 27726  
 27727  		radiusTop = radiusTop !== undefined ? radiusTop : 20;
 27728  		radiusBottom = radiusBottom !== undefined ? radiusBottom : 20;
 27729  		height = height !== undefined ? height : 100;
 27730  
 27731  		radialSegments = Math.floor( radialSegments ) || 8;
 27732  		heightSegments = Math.floor( heightSegments ) || 1;
 27733  
 27734  		openEnded = openEnded !== undefined ? openEnded : false;
 27735  		thetaStart = thetaStart !== undefined ? thetaStart : 0.0;
 27736  		thetaLength = thetaLength !== undefined ? thetaLength : 2.0 * Math.PI;
 27737  
 27738  		// buffers
 27739  
 27740  		var indices = [];
 27741  		var vertices = [];
 27742  		var normals = [];
 27743  		var uvs = [];
 27744  
 27745  		// helper variables
 27746  
 27747  		var index = 0;
 27748  		var indexOffset = 0;
 27749  		var indexArray = [];
 27750  		var halfHeight = height / 2;
 27751  		var groupStart = 0;
 27752  
 27753  		// generate geometry
 27754  
 27755  		generateTorso();
 27756  
 27757  		if ( openEnded === false ) {
 27758  
 27759  			if ( radiusTop > 0 ) generateCap( true );
 27760  			if ( radiusBottom > 0 ) generateCap( false );
 27761  
 27762  		}
 27763  
 27764  		// build geometry
 27765  
 27766  		this.setIndex( indices );
 27767  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 27768  		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
 27769  		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 27770  
 27771  		function generateTorso() {
 27772  
 27773  			var x, y;
 27774  			var normal = new Vector3();
 27775  			var vertex = new Vector3();
 27776  
 27777  			var groupCount = 0;
 27778  
 27779  			// this will be used to calculate the normal
 27780  			var slope = ( radiusBottom - radiusTop ) / height;
 27781  
 27782  			// generate vertices, normals and uvs
 27783  
 27784  			for ( y = 0; y <= heightSegments; y ++ ) {
 27785  
 27786  				var indexRow = [];
 27787  
 27788  				var v = y / heightSegments;
 27789  
 27790  				// calculate the radius of the current row
 27791  
 27792  				var radius = v * ( radiusBottom - radiusTop ) + radiusTop;
 27793  
 27794  				for ( x = 0; x <= radialSegments; x ++ ) {
 27795  
 27796  					var u = x / radialSegments;
 27797  
 27798  					var theta = u * thetaLength + thetaStart;
 27799  
 27800  					var sinTheta = Math.sin( theta );
 27801  					var cosTheta = Math.cos( theta );
 27802  
 27803  					// vertex
 27804  
 27805  					vertex.x = radius * sinTheta;
 27806  					vertex.y = - v * height + halfHeight;
 27807  					vertex.z = radius * cosTheta;
 27808  					vertices.push( vertex.x, vertex.y, vertex.z );
 27809  
 27810  					// normal
 27811  
 27812  					normal.set( sinTheta, slope, cosTheta ).normalize();
 27813  					normals.push( normal.x, normal.y, normal.z );
 27814  
 27815  					// uv
 27816  
 27817  					uvs.push( u, 1 - v );
 27818  
 27819  					// save index of vertex in respective row
 27820  
 27821  					indexRow.push( index ++ );
 27822  
 27823  				}
 27824  
 27825  				// now save vertices of the row in our index array
 27826  
 27827  				indexArray.push( indexRow );
 27828  
 27829  			}
 27830  
 27831  			// generate indices
 27832  
 27833  			for ( x = 0; x < radialSegments; x ++ ) {
 27834  
 27835  				for ( y = 0; y < heightSegments; y ++ ) {
 27836  
 27837  					// we use the index array to access the correct indices
 27838  
 27839  					var a = indexArray[ y ][ x ];
 27840  					var b = indexArray[ y + 1 ][ x ];
 27841  					var c = indexArray[ y + 1 ][ x + 1 ];
 27842  					var d = indexArray[ y ][ x + 1 ];
 27843  
 27844  					// faces
 27845  
 27846  					indices.push( a, b, d );
 27847  					indices.push( b, c, d );
 27848  
 27849  					// update group counter
 27850  
 27851  					groupCount += 6;
 27852  
 27853  				}
 27854  
 27855  			}
 27856  
 27857  			// add a group to the geometry. this will ensure multi material support
 27858  
 27859  			scope.addGroup( groupStart, groupCount, 0 );
 27860  
 27861  			// calculate new start value for groups
 27862  
 27863  			groupStart += groupCount;
 27864  
 27865  		}
 27866  
 27867  		function generateCap( top ) {
 27868  
 27869  			var x, centerIndexStart, centerIndexEnd;
 27870  
 27871  			var uv = new Vector2();
 27872  			var vertex = new Vector3();
 27873  
 27874  			var groupCount = 0;
 27875  
 27876  			var radius = ( top === true ) ? radiusTop : radiusBottom;
 27877  			var sign = ( top === true ) ? 1 : - 1;
 27878  
 27879  			// save the index of the first center vertex
 27880  			centerIndexStart = index;
 27881  
 27882  			// first we generate the center vertex data of the cap.
 27883  			// because the geometry needs one set of uvs per face,
 27884  			// we must generate a center vertex per face/segment
 27885  
 27886  			for ( x = 1; x <= radialSegments; x ++ ) {
 27887  
 27888  				// vertex
 27889  
 27890  				vertices.push( 0, halfHeight * sign, 0 );
 27891  
 27892  				// normal
 27893  
 27894  				normals.push( 0, sign, 0 );
 27895  
 27896  				// uv
 27897  
 27898  				uvs.push( 0.5, 0.5 );
 27899  
 27900  				// increase index
 27901  
 27902  				index ++;
 27903  
 27904  			}
 27905  
 27906  			// save the index of the last center vertex
 27907  
 27908  			centerIndexEnd = index;
 27909  
 27910  			// now we generate the surrounding vertices, normals and uvs
 27911  
 27912  			for ( x = 0; x <= radialSegments; x ++ ) {
 27913  
 27914  				var u = x / radialSegments;
 27915  				var theta = u * thetaLength + thetaStart;
 27916  
 27917  				var cosTheta = Math.cos( theta );
 27918  				var sinTheta = Math.sin( theta );
 27919  
 27920  				// vertex
 27921  
 27922  				vertex.x = radius * sinTheta;
 27923  				vertex.y = halfHeight * sign;
 27924  				vertex.z = radius * cosTheta;
 27925  				vertices.push( vertex.x, vertex.y, vertex.z );
 27926  
 27927  				// normal
 27928  
 27929  				normals.push( 0, sign, 0 );
 27930  
 27931  				// uv
 27932  
 27933  				uv.x = ( cosTheta * 0.5 ) + 0.5;
 27934  				uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
 27935  				uvs.push( uv.x, uv.y );
 27936  
 27937  				// increase index
 27938  
 27939  				index ++;
 27940  
 27941  			}
 27942  
 27943  			// generate indices
 27944  
 27945  			for ( x = 0; x < radialSegments; x ++ ) {
 27946  
 27947  				var c = centerIndexStart + x;
 27948  				var i = centerIndexEnd + x;
 27949  
 27950  				if ( top === true ) {
 27951  
 27952  					// face top
 27953  
 27954  					indices.push( i, i + 1, c );
 27955  
 27956  				} else {
 27957  
 27958  					// face bottom
 27959  
 27960  					indices.push( i + 1, i, c );
 27961  
 27962  				}
 27963  
 27964  				groupCount += 3;
 27965  
 27966  			}
 27967  
 27968  			// add a group to the geometry. this will ensure multi material support
 27969  
 27970  			scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
 27971  
 27972  			// calculate new start value for groups
 27973  
 27974  			groupStart += groupCount;
 27975  
 27976  		}
 27977  
 27978  	}
 27979  
 27980  	CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 27981  	CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry;
 27982  
 27983  	/**
 27984  	 * @author abelnation / http://github.com/abelnation
 27985  	 */
 27986  
 27987  	function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
 27988  
 27989  		CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
 27990  
 27991  		this.type = 'ConeGeometry';
 27992  
 27993  		this.parameters = {
 27994  			radius: radius,
 27995  			height: height,
 27996  			radialSegments: radialSegments,
 27997  			heightSegments: heightSegments,
 27998  			openEnded: openEnded,
 27999  			thetaStart: thetaStart,
 28000  			thetaLength: thetaLength
 28001  		};
 28002  
 28003  	}
 28004  
 28005  	ConeGeometry.prototype = Object.create( CylinderGeometry.prototype );
 28006  	ConeGeometry.prototype.constructor = ConeGeometry;
 28007  
 28008  	/**
 28009  	 * @author: abelnation / http://github.com/abelnation
 28010  	 */
 28011  
 28012  	function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
 28013  
 28014  		CylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
 28015  
 28016  		this.type = 'ConeBufferGeometry';
 28017  
 28018  		this.parameters = {
 28019  			radius: radius,
 28020  			height: height,
 28021  			radialSegments: radialSegments,
 28022  			heightSegments: heightSegments,
 28023  			openEnded: openEnded,
 28024  			thetaStart: thetaStart,
 28025  			thetaLength: thetaLength
 28026  		};
 28027  
 28028  	}
 28029  
 28030  	ConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype );
 28031  	ConeBufferGeometry.prototype.constructor = ConeBufferGeometry;
 28032  
 28033  	/**
 28034  	 * @author hughes
 28035  	 */
 28036  
 28037  	function CircleGeometry( radius, segments, thetaStart, thetaLength ) {
 28038  
 28039  		Geometry.call( this );
 28040  
 28041  		this.type = 'CircleGeometry';
 28042  
 28043  		this.parameters = {
 28044  			radius: radius,
 28045  			segments: segments,
 28046  			thetaStart: thetaStart,
 28047  			thetaLength: thetaLength
 28048  		};
 28049  
 28050  		this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) );
 28051  
 28052  	}
 28053  
 28054  	CircleGeometry.prototype = Object.create( Geometry.prototype );
 28055  	CircleGeometry.prototype.constructor = CircleGeometry;
 28056  
 28057  	/**
 28058  	 * @author benaadams / https://twitter.com/ben_a_adams
 28059  	 * @author Mugen87 / https://github.com/Mugen87
 28060  	 */
 28061  
 28062  	function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) {
 28063  
 28064  		BufferGeometry.call( this );
 28065  
 28066  		this.type = 'CircleBufferGeometry';
 28067  
 28068  		this.parameters = {
 28069  			radius: radius,
 28070  			segments: segments,
 28071  			thetaStart: thetaStart,
 28072  			thetaLength: thetaLength
 28073  		};
 28074  
 28075  		radius = radius || 50;
 28076  		segments = segments !== undefined ? Math.max( 3, segments ) : 8;
 28077  
 28078  		thetaStart = thetaStart !== undefined ? thetaStart : 0;
 28079  		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
 28080  
 28081  		// buffers
 28082  
 28083  		var indices = [];
 28084  		var vertices = [];
 28085  		var normals = [];
 28086  		var uvs = [];
 28087  
 28088  		// helper variables
 28089  
 28090  		var i, s;
 28091  		var vertex = new Vector3();
 28092  		var uv = new Vector2();
 28093  
 28094  		// center point
 28095  
 28096  		vertices.push( 0, 0, 0 );
 28097  		normals.push( 0, 0, 1 );
 28098  		uvs.push( 0.5, 0.5 );
 28099  
 28100  		for ( s = 0, i = 3; s <= segments; s ++, i += 3 ) {
 28101  
 28102  			var segment = thetaStart + s / segments * thetaLength;
 28103  
 28104  			// vertex
 28105  
 28106  			vertex.x = radius * Math.cos( segment );
 28107  			vertex.y = radius * Math.sin( segment );
 28108  
 28109  			vertices.push( vertex.x, vertex.y, vertex.z );
 28110  
 28111  			// normal
 28112  
 28113  			normals.push( 0, 0, 1 );
 28114  
 28115  			// uvs
 28116  
 28117  			uv.x = ( vertices[ i ] / radius + 1 ) / 2;
 28118  			uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
 28119  
 28120  			uvs.push( uv.x, uv.y );
 28121  
 28122  		}
 28123  
 28124  		// indices
 28125  
 28126  		for ( i = 1; i <= segments; i ++ ) {
 28127  
 28128  			indices.push( i, i + 1, 0 );
 28129  
 28130  		}
 28131  
 28132  		// build geometry
 28133  
 28134  		this.setIndex( indices );
 28135  		this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 28136  		this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
 28137  		this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 28138  
 28139  	}
 28140  
 28141  	CircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 28142  	CircleBufferGeometry.prototype.constructor = CircleBufferGeometry;
 28143  
 28144  
 28145  
 28146  	var Geometries = Object.freeze({
 28147  		WireframeGeometry: WireframeGeometry,
 28148  		ParametricGeometry: ParametricGeometry,
 28149  		ParametricBufferGeometry: ParametricBufferGeometry,
 28150  		TetrahedronGeometry: TetrahedronGeometry,
 28151  		TetrahedronBufferGeometry: TetrahedronBufferGeometry,
 28152  		OctahedronGeometry: OctahedronGeometry,
 28153  		OctahedronBufferGeometry: OctahedronBufferGeometry,
 28154  		IcosahedronGeometry: IcosahedronGeometry,
 28155  		IcosahedronBufferGeometry: IcosahedronBufferGeometry,
 28156  		DodecahedronGeometry: DodecahedronGeometry,
 28157  		DodecahedronBufferGeometry: DodecahedronBufferGeometry,
 28158  		PolyhedronGeometry: PolyhedronGeometry,
 28159  		PolyhedronBufferGeometry: PolyhedronBufferGeometry,
 28160  		TubeGeometry: TubeGeometry,
 28161  		TubeBufferGeometry: TubeBufferGeometry,
 28162  		TorusKnotGeometry: TorusKnotGeometry,
 28163  		TorusKnotBufferGeometry: TorusKnotBufferGeometry,
 28164  		TorusGeometry: TorusGeometry,
 28165  		TorusBufferGeometry: TorusBufferGeometry,
 28166  		TextGeometry: TextGeometry,
 28167  		SphereGeometry: SphereGeometry,
 28168  		SphereBufferGeometry: SphereBufferGeometry,
 28169  		RingGeometry: RingGeometry,
 28170  		RingBufferGeometry: RingBufferGeometry,
 28171  		PlaneGeometry: PlaneGeometry,
 28172  		PlaneBufferGeometry: PlaneBufferGeometry,
 28173  		LatheGeometry: LatheGeometry,
 28174  		LatheBufferGeometry: LatheBufferGeometry,
 28175  		ShapeGeometry: ShapeGeometry,
 28176  		ShapeBufferGeometry: ShapeBufferGeometry,
 28177  		ExtrudeGeometry: ExtrudeGeometry,
 28178  		EdgesGeometry: EdgesGeometry,
 28179  		ConeGeometry: ConeGeometry,
 28180  		ConeBufferGeometry: ConeBufferGeometry,
 28181  		CylinderGeometry: CylinderGeometry,
 28182  		CylinderBufferGeometry: CylinderBufferGeometry,
 28183  		CircleGeometry: CircleGeometry,
 28184  		CircleBufferGeometry: CircleBufferGeometry,
 28185  		BoxGeometry: BoxGeometry,
 28186  		BoxBufferGeometry: BoxBufferGeometry
 28187  	});
 28188  
 28189  	/**
 28190  	 * @author mrdoob / http://mrdoob.com/
 28191  	 */
 28192  
 28193  	function ShadowMaterial() {
 28194  
 28195  		ShaderMaterial.call( this, {
 28196  			uniforms: UniformsUtils.merge( [
 28197  				UniformsLib.lights,
 28198  				{
 28199  					opacity: { value: 1.0 }
 28200  				}
 28201  			] ),
 28202  			vertexShader: ShaderChunk[ 'shadow_vert' ],
 28203  			fragmentShader: ShaderChunk[ 'shadow_frag' ]
 28204  		} );
 28205  
 28206  		this.lights = true;
 28207  		this.transparent = true;
 28208  
 28209  		Object.defineProperties( this, {
 28210  			opacity: {
 28211  				enumerable: true,
 28212  				get: function () {
 28213  					return this.uniforms.opacity.value;
 28214  				},
 28215  				set: function ( value ) {
 28216  					this.uniforms.opacity.value = value;
 28217  				}
 28218  			}
 28219  		} );
 28220  
 28221  	}
 28222  
 28223  	ShadowMaterial.prototype = Object.create( ShaderMaterial.prototype );
 28224  	ShadowMaterial.prototype.constructor = ShadowMaterial;
 28225  
 28226  	ShadowMaterial.prototype.isShadowMaterial = true;
 28227  
 28228  	/**
 28229  	 * @author mrdoob / http://mrdoob.com/
 28230  	 */
 28231  
 28232  	function RawShaderMaterial( parameters ) {
 28233  
 28234  		ShaderMaterial.call( this, parameters );
 28235  
 28236  		this.type = 'RawShaderMaterial';
 28237  
 28238  	}
 28239  
 28240  	RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype );
 28241  	RawShaderMaterial.prototype.constructor = RawShaderMaterial;
 28242  
 28243  	RawShaderMaterial.prototype.isRawShaderMaterial = true;
 28244  
 28245  	/**
 28246  	 * @author mrdoob / http://mrdoob.com/
 28247  	 */
 28248  
 28249  	function MultiMaterial( materials ) {
 28250  
 28251  		this.uuid = _Math.generateUUID();
 28252  
 28253  		this.type = 'MultiMaterial';
 28254  
 28255  		this.materials = Array.isArray( materials ) ? materials : [];
 28256  
 28257  		this.visible = true;
 28258  
 28259  	}
 28260  
 28261  	MultiMaterial.prototype = {
 28262  
 28263  		constructor: MultiMaterial,
 28264  
 28265  		isMultiMaterial: true,
 28266  
 28267  		toJSON: function ( meta ) {
 28268  
 28269  			var output = {
 28270  				metadata: {
 28271  					version: 4.2,
 28272  					type: 'material',
 28273  					generator: 'MaterialExporter'
 28274  				},
 28275  				uuid: this.uuid,
 28276  				type: this.type,
 28277  				materials: []
 28278  			};
 28279  
 28280  			var materials = this.materials;
 28281  
 28282  			for ( var i = 0, l = materials.length; i < l; i ++ ) {
 28283  
 28284  				var material = materials[ i ].toJSON( meta );
 28285  				delete material.metadata;
 28286  
 28287  				output.materials.push( material );
 28288  
 28289  			}
 28290  
 28291  			output.visible = this.visible;
 28292  
 28293  			return output;
 28294  
 28295  		},
 28296  
 28297  		clone: function () {
 28298  
 28299  			var material = new this.constructor();
 28300  
 28301  			for ( var i = 0; i < this.materials.length; i ++ ) {
 28302  
 28303  				material.materials.push( this.materials[ i ].clone() );
 28304  
 28305  			}
 28306  
 28307  			material.visible = this.visible;
 28308  
 28309  			return material;
 28310  
 28311  		}
 28312  
 28313  	};
 28314  
 28315  	/**
 28316  	 * @author WestLangley / http://github.com/WestLangley
 28317  	 *
 28318  	 * parameters = {
 28319  	 *  color: <hex>,
 28320  	 *  roughness: <float>,
 28321  	 *  metalness: <float>,
 28322  	 *  opacity: <float>,
 28323  	 *
 28324  	 *  map: new THREE.Texture( <Image> ),
 28325  	 *
 28326  	 *  lightMap: new THREE.Texture( <Image> ),
 28327  	 *  lightMapIntensity: <float>
 28328  	 *
 28329  	 *  aoMap: new THREE.Texture( <Image> ),
 28330  	 *  aoMapIntensity: <float>
 28331  	 *
 28332  	 *  emissive: <hex>,
 28333  	 *  emissiveIntensity: <float>
 28334  	 *  emissiveMap: new THREE.Texture( <Image> ),
 28335  	 *
 28336  	 *  bumpMap: new THREE.Texture( <Image> ),
 28337  	 *  bumpScale: <float>,
 28338  	 *
 28339  	 *  normalMap: new THREE.Texture( <Image> ),
 28340  	 *  normalScale: <Vector2>,
 28341  	 *
 28342  	 *  displacementMap: new THREE.Texture( <Image> ),
 28343  	 *  displacementScale: <float>,
 28344  	 *  displacementBias: <float>,
 28345  	 *
 28346  	 *  roughnessMap: new THREE.Texture( <Image> ),
 28347  	 *
 28348  	 *  metalnessMap: new THREE.Texture( <Image> ),
 28349  	 *
 28350  	 *  alphaMap: new THREE.Texture( <Image> ),
 28351  	 *
 28352  	 *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
 28353  	 *  envMapIntensity: <float>
 28354  	 *
 28355  	 *  refractionRatio: <float>,
 28356  	 *
 28357  	 *  wireframe: <boolean>,
 28358  	 *  wireframeLinewidth: <float>,
 28359  	 *
 28360  	 *  skinning: <bool>,
 28361  	 *  morphTargets: <bool>,
 28362  	 *  morphNormals: <bool>
 28363  	 * }
 28364  	 */
 28365  
 28366  	function MeshStandardMaterial( parameters ) {
 28367  
 28368  		Material.call( this );
 28369  
 28370  		this.defines = { 'STANDARD': '' };
 28371  
 28372  		this.type = 'MeshStandardMaterial';
 28373  
 28374  		this.color = new Color( 0xffffff ); // diffuse
 28375  		this.roughness = 0.5;
 28376  		this.metalness = 0.5;
 28377  
 28378  		this.map = null;
 28379  
 28380  		this.lightMap = null;
 28381  		this.lightMapIntensity = 1.0;
 28382  
 28383  		this.aoMap = null;
 28384  		this.aoMapIntensity = 1.0;
 28385  
 28386  		this.emissive = new Color( 0x000000 );
 28387  		this.emissiveIntensity = 1.0;
 28388  		this.emissiveMap = null;
 28389  
 28390  		this.bumpMap = null;
 28391  		this.bumpScale = 1;
 28392  
 28393  		this.normalMap = null;
 28394  		this.normalScale = new Vector2( 1, 1 );
 28395  
 28396  		this.displacementMap = null;
 28397  		this.displacementScale = 1;
 28398  		this.displacementBias = 0;
 28399  
 28400  		this.roughnessMap = null;
 28401  
 28402  		this.metalnessMap = null;
 28403  
 28404  		this.alphaMap = null;
 28405  
 28406  		this.envMap = null;
 28407  		this.envMapIntensity = 1.0;
 28408  
 28409  		this.refractionRatio = 0.98;
 28410  
 28411  		this.wireframe = false;
 28412  		this.wireframeLinewidth = 1;
 28413  		this.wireframeLinecap = 'round';
 28414  		this.wireframeLinejoin = 'round';
 28415  
 28416  		this.skinning = false;
 28417  		this.morphTargets = false;
 28418  		this.morphNormals = false;
 28419  
 28420  		this.setValues( parameters );
 28421  
 28422  	}
 28423  
 28424  	MeshStandardMaterial.prototype = Object.create( Material.prototype );
 28425  	MeshStandardMaterial.prototype.constructor = MeshStandardMaterial;
 28426  
 28427  	MeshStandardMaterial.prototype.isMeshStandardMaterial = true;
 28428  
 28429  	MeshStandardMaterial.prototype.copy = function ( source ) {
 28430  
 28431  		Material.prototype.copy.call( this, source );
 28432  
 28433  		this.defines = { 'STANDARD': '' };
 28434  
 28435  		this.color.copy( source.color );
 28436  		this.roughness = source.roughness;
 28437  		this.metalness = source.metalness;
 28438  
 28439  		this.map = source.map;
 28440  
 28441  		this.lightMap = source.lightMap;
 28442  		this.lightMapIntensity = source.lightMapIntensity;
 28443  
 28444  		this.aoMap = source.aoMap;
 28445  		this.aoMapIntensity = source.aoMapIntensity;
 28446  
 28447  		this.emissive.copy( source.emissive );
 28448  		this.emissiveMap = source.emissiveMap;
 28449  		this.emissiveIntensity = source.emissiveIntensity;
 28450  
 28451  		this.bumpMap = source.bumpMap;
 28452  		this.bumpScale = source.bumpScale;
 28453  
 28454  		this.normalMap = source.normalMap;
 28455  		this.normalScale.copy( source.normalScale );
 28456  
 28457  		this.displacementMap = source.displacementMap;
 28458  		this.displacementScale = source.displacementScale;
 28459  		this.displacementBias = source.displacementBias;
 28460  
 28461  		this.roughnessMap = source.roughnessMap;
 28462  
 28463  		this.metalnessMap = source.metalnessMap;
 28464  
 28465  		this.alphaMap = source.alphaMap;
 28466  
 28467  		this.envMap = source.envMap;
 28468  		this.envMapIntensity = source.envMapIntensity;
 28469  
 28470  		this.refractionRatio = source.refractionRatio;
 28471  
 28472  		this.wireframe = source.wireframe;
 28473  		this.wireframeLinewidth = source.wireframeLinewidth;
 28474  		this.wireframeLinecap = source.wireframeLinecap;
 28475  		this.wireframeLinejoin = source.wireframeLinejoin;
 28476  
 28477  		this.skinning = source.skinning;
 28478  		this.morphTargets = source.morphTargets;
 28479  		this.morphNormals = source.morphNormals;
 28480  
 28481  		return this;
 28482  
 28483  	};
 28484  
 28485  	/**
 28486  	 * @author WestLangley / http://github.com/WestLangley
 28487  	 *
 28488  	 * parameters = {
 28489  	 *  reflectivity: <float>
 28490  	 * }
 28491  	 */
 28492  
 28493  	function MeshPhysicalMaterial( parameters ) {
 28494  
 28495  		MeshStandardMaterial.call( this );
 28496  
 28497  		this.defines = { 'PHYSICAL': '' };
 28498  
 28499  		this.type = 'MeshPhysicalMaterial';
 28500  
 28501  		this.reflectivity = 0.5; // maps to F0 = 0.04
 28502  
 28503  		this.clearCoat = 0.0;
 28504  		this.clearCoatRoughness = 0.0;
 28505  
 28506  		this.setValues( parameters );
 28507  
 28508  	}
 28509  
 28510  	MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype );
 28511  	MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial;
 28512  
 28513  	MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true;
 28514  
 28515  	MeshPhysicalMaterial.prototype.copy = function ( source ) {
 28516  
 28517  		MeshStandardMaterial.prototype.copy.call( this, source );
 28518  
 28519  		this.defines = { 'PHYSICAL': '' };
 28520  
 28521  		this.reflectivity = source.reflectivity;
 28522  
 28523  		this.clearCoat = source.clearCoat;
 28524  		this.clearCoatRoughness = source.clearCoatRoughness;
 28525  
 28526  		return this;
 28527  
 28528  	};
 28529  
 28530  	/**
 28531  	 * @author mrdoob / http://mrdoob.com/
 28532  	 * @author alteredq / http://alteredqualia.com/
 28533  	 *
 28534  	 * parameters = {
 28535  	 *  color: <hex>,
 28536  	 *  specular: <hex>,
 28537  	 *  shininess: <float>,
 28538  	 *  opacity: <float>,
 28539  	 *
 28540  	 *  map: new THREE.Texture( <Image> ),
 28541  	 *
 28542  	 *  lightMap: new THREE.Texture( <Image> ),
 28543  	 *  lightMapIntensity: <float>
 28544  	 *
 28545  	 *  aoMap: new THREE.Texture( <Image> ),
 28546  	 *  aoMapIntensity: <float>
 28547  	 *
 28548  	 *  emissive: <hex>,
 28549  	 *  emissiveIntensity: <float>
 28550  	 *  emissiveMap: new THREE.Texture( <Image> ),
 28551  	 *
 28552  	 *  bumpMap: new THREE.Texture( <Image> ),
 28553  	 *  bumpScale: <float>,
 28554  	 *
 28555  	 *  normalMap: new THREE.Texture( <Image> ),
 28556  	 *  normalScale: <Vector2>,
 28557  	 *
 28558  	 *  displacementMap: new THREE.Texture( <Image> ),
 28559  	 *  displacementScale: <float>,
 28560  	 *  displacementBias: <float>,
 28561  	 *
 28562  	 *  specularMap: new THREE.Texture( <Image> ),
 28563  	 *
 28564  	 *  alphaMap: new THREE.Texture( <Image> ),
 28565  	 *
 28566  	 *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
 28567  	 *  combine: THREE.Multiply,
 28568  	 *  reflectivity: <float>,
 28569  	 *  refractionRatio: <float>,
 28570  	 *
 28571  	 *  wireframe: <boolean>,
 28572  	 *  wireframeLinewidth: <float>,
 28573  	 *
 28574  	 *  skinning: <bool>,
 28575  	 *  morphTargets: <bool>,
 28576  	 *  morphNormals: <bool>
 28577  	 * }
 28578  	 */
 28579  
 28580  	function MeshPhongMaterial( parameters ) {
 28581  
 28582  		Material.call( this );
 28583  
 28584  		this.type = 'MeshPhongMaterial';
 28585  
 28586  		this.color = new Color( 0xffffff ); // diffuse
 28587  		this.specular = new Color( 0x111111 );
 28588  		this.shininess = 30;
 28589  
 28590  		this.map = null;
 28591  
 28592  		this.lightMap = null;
 28593  		this.lightMapIntensity = 1.0;
 28594  
 28595  		this.aoMap = null;
 28596  		this.aoMapIntensity = 1.0;
 28597  
 28598  		this.emissive = new Color( 0x000000 );
 28599  		this.emissiveIntensity = 1.0;
 28600  		this.emissiveMap = null;
 28601  
 28602  		this.bumpMap = null;
 28603  		this.bumpScale = 1;
 28604  
 28605  		this.normalMap = null;
 28606  		this.normalScale = new Vector2( 1, 1 );
 28607  
 28608  		this.displacementMap = null;
 28609  		this.displacementScale = 1;
 28610  		this.displacementBias = 0;
 28611  
 28612  		this.specularMap = null;
 28613  
 28614  		this.alphaMap = null;
 28615  
 28616  		this.envMap = null;
 28617  		this.combine = MultiplyOperation;
 28618  		this.reflectivity = 1;
 28619  		this.refractionRatio = 0.98;
 28620  
 28621  		this.wireframe = false;
 28622  		this.wireframeLinewidth = 1;
 28623  		this.wireframeLinecap = 'round';
 28624  		this.wireframeLinejoin = 'round';
 28625  
 28626  		this.skinning = false;
 28627  		this.morphTargets = false;
 28628  		this.morphNormals = false;
 28629  
 28630  		this.setValues( parameters );
 28631  
 28632  	}
 28633  
 28634  	MeshPhongMaterial.prototype = Object.create( Material.prototype );
 28635  	MeshPhongMaterial.prototype.constructor = MeshPhongMaterial;
 28636  
 28637  	MeshPhongMaterial.prototype.isMeshPhongMaterial = true;
 28638  
 28639  	MeshPhongMaterial.prototype.copy = function ( source ) {
 28640  
 28641  		Material.prototype.copy.call( this, source );
 28642  
 28643  		this.color.copy( source.color );
 28644  		this.specular.copy( source.specular );
 28645  		this.shininess = source.shininess;
 28646  
 28647  		this.map = source.map;
 28648  
 28649  		this.lightMap = source.lightMap;
 28650  		this.lightMapIntensity = source.lightMapIntensity;
 28651  
 28652  		this.aoMap = source.aoMap;
 28653  		this.aoMapIntensity = source.aoMapIntensity;
 28654  
 28655  		this.emissive.copy( source.emissive );
 28656  		this.emissiveMap = source.emissiveMap;
 28657  		this.emissiveIntensity = source.emissiveIntensity;
 28658  
 28659  		this.bumpMap = source.bumpMap;
 28660  		this.bumpScale = source.bumpScale;
 28661  
 28662  		this.normalMap = source.normalMap;
 28663  		this.normalScale.copy( source.normalScale );
 28664  
 28665  		this.displacementMap = source.displacementMap;
 28666  		this.displacementScale = source.displacementScale;
 28667  		this.displacementBias = source.displacementBias;
 28668  
 28669  		this.specularMap = source.specularMap;
 28670  
 28671  		this.alphaMap = source.alphaMap;
 28672  
 28673  		this.envMap = source.envMap;
 28674  		this.combine = source.combine;
 28675  		this.reflectivity = source.reflectivity;
 28676  		this.refractionRatio = source.refractionRatio;
 28677  
 28678  		this.wireframe = source.wireframe;
 28679  		this.wireframeLinewidth = source.wireframeLinewidth;
 28680  		this.wireframeLinecap = source.wireframeLinecap;
 28681  		this.wireframeLinejoin = source.wireframeLinejoin;
 28682  
 28683  		this.skinning = source.skinning;
 28684  		this.morphTargets = source.morphTargets;
 28685  		this.morphNormals = source.morphNormals;
 28686  
 28687  		return this;
 28688  
 28689  	};
 28690  
 28691  	/**
 28692  	 * @author takahirox / http://github.com/takahirox
 28693  	 *
 28694  	 * parameters = {
 28695  	 *  gradientMap: new THREE.Texture( <Image> )
 28696  	 * }
 28697  	 */
 28698  
 28699  	function MeshToonMaterial( parameters ) {
 28700  
 28701  		MeshPhongMaterial.call( this );
 28702  
 28703  		this.defines = { 'TOON': '' };
 28704  
 28705  		this.type = 'MeshToonMaterial';
 28706  
 28707  		this.gradientMap = null;
 28708  
 28709  		this.setValues( parameters );
 28710  
 28711  	}
 28712  
 28713  	MeshToonMaterial.prototype = Object.create( MeshPhongMaterial.prototype );
 28714  	MeshToonMaterial.prototype.constructor = MeshToonMaterial;
 28715  
 28716  	MeshToonMaterial.prototype.isMeshToonMaterial = true;
 28717  
 28718  	MeshToonMaterial.prototype.copy = function ( source ) {
 28719  
 28720  		MeshPhongMaterial.prototype.copy.call( this, source );
 28721  
 28722  		this.gradientMap = source.gradientMap;
 28723  
 28724  		return this;
 28725  
 28726  	};
 28727  
 28728  	/**
 28729  	 * @author mrdoob / http://mrdoob.com/
 28730  	 * @author WestLangley / http://github.com/WestLangley
 28731  	 *
 28732  	 * parameters = {
 28733  	 *  opacity: <float>,
 28734  	 *
 28735  	 *  bumpMap: new THREE.Texture( <Image> ),
 28736  	 *  bumpScale: <float>,
 28737  	 *
 28738  	 *  normalMap: new THREE.Texture( <Image> ),
 28739  	 *  normalScale: <Vector2>,
 28740  	 *
 28741  	 *  displacementMap: new THREE.Texture( <Image> ),
 28742  	 *  displacementScale: <float>,
 28743  	 *  displacementBias: <float>,
 28744  	 *
 28745  	 *  wireframe: <boolean>,
 28746  	 *  wireframeLinewidth: <float>
 28747  	 *
 28748  	 *  skinning: <bool>,
 28749  	 *  morphTargets: <bool>,
 28750  	 *  morphNormals: <bool>
 28751  	 * }
 28752  	 */
 28753  
 28754  	function MeshNormalMaterial( parameters ) {
 28755  
 28756  		Material.call( this, parameters );
 28757  
 28758  		this.type = 'MeshNormalMaterial';
 28759  
 28760  		this.bumpMap = null;
 28761  		this.bumpScale = 1;
 28762  
 28763  		this.normalMap = null;
 28764  		this.normalScale = new Vector2( 1, 1 );
 28765  
 28766  		this.displacementMap = null;
 28767  		this.displacementScale = 1;
 28768  		this.displacementBias = 0;
 28769  
 28770  		this.wireframe = false;
 28771  		this.wireframeLinewidth = 1;
 28772  
 28773  		this.fog = false;
 28774  		this.lights = false;
 28775  
 28776  		this.skinning = false;
 28777  		this.morphTargets = false;
 28778  		this.morphNormals = false;
 28779  
 28780  		this.setValues( parameters );
 28781  
 28782  	}
 28783  
 28784  	MeshNormalMaterial.prototype = Object.create( Material.prototype );
 28785  	MeshNormalMaterial.prototype.constructor = MeshNormalMaterial;
 28786  
 28787  	MeshNormalMaterial.prototype.isMeshNormalMaterial = true;
 28788  
 28789  	MeshNormalMaterial.prototype.copy = function ( source ) {
 28790  
 28791  		Material.prototype.copy.call( this, source );
 28792  
 28793  		this.bumpMap = source.bumpMap;
 28794  		this.bumpScale = source.bumpScale;
 28795  
 28796  		this.normalMap = source.normalMap;
 28797  		this.normalScale.copy( source.normalScale );
 28798  
 28799  		this.displacementMap = source.displacementMap;
 28800  		this.displacementScale = source.displacementScale;
 28801  		this.displacementBias = source.displacementBias;
 28802  
 28803  		this.wireframe = source.wireframe;
 28804  		this.wireframeLinewidth = source.wireframeLinewidth;
 28805  
 28806  		this.skinning = source.skinning;
 28807  		this.morphTargets = source.morphTargets;
 28808  		this.morphNormals = source.morphNormals;
 28809  
 28810  		return this;
 28811  
 28812  	};
 28813  
 28814  	/**
 28815  	 * @author mrdoob / http://mrdoob.com/
 28816  	 * @author alteredq / http://alteredqualia.com/
 28817  	 *
 28818  	 * parameters = {
 28819  	 *  color: <hex>,
 28820  	 *  opacity: <float>,
 28821  	 *
 28822  	 *  map: new THREE.Texture( <Image> ),
 28823  	 *
 28824  	 *  lightMap: new THREE.Texture( <Image> ),
 28825  	 *  lightMapIntensity: <float>
 28826  	 *
 28827  	 *  aoMap: new THREE.Texture( <Image> ),
 28828  	 *  aoMapIntensity: <float>
 28829  	 *
 28830  	 *  emissive: <hex>,
 28831  	 *  emissiveIntensity: <float>
 28832  	 *  emissiveMap: new THREE.Texture( <Image> ),
 28833  	 *
 28834  	 *  specularMap: new THREE.Texture( <Image> ),
 28835  	 *
 28836  	 *  alphaMap: new THREE.Texture( <Image> ),
 28837  	 *
 28838  	 *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
 28839  	 *  combine: THREE.Multiply,
 28840  	 *  reflectivity: <float>,
 28841  	 *  refractionRatio: <float>,
 28842  	 *
 28843  	 *  wireframe: <boolean>,
 28844  	 *  wireframeLinewidth: <float>,
 28845  	 *
 28846  	 *  skinning: <bool>,
 28847  	 *  morphTargets: <bool>,
 28848  	 *  morphNormals: <bool>
 28849  	 * }
 28850  	 */
 28851  
 28852  	function MeshLambertMaterial( parameters ) {
 28853  
 28854  		Material.call( this );
 28855  
 28856  		this.type = 'MeshLambertMaterial';
 28857  
 28858  		this.color = new Color( 0xffffff ); // diffuse
 28859  
 28860  		this.map = null;
 28861  
 28862  		this.lightMap = null;
 28863  		this.lightMapIntensity = 1.0;
 28864  
 28865  		this.aoMap = null;
 28866  		this.aoMapIntensity = 1.0;
 28867  
 28868  		this.emissive = new Color( 0x000000 );
 28869  		this.emissiveIntensity = 1.0;
 28870  		this.emissiveMap = null;
 28871  
 28872  		this.specularMap = null;
 28873  
 28874  		this.alphaMap = null;
 28875  
 28876  		this.envMap = null;
 28877  		this.combine = MultiplyOperation;
 28878  		this.reflectivity = 1;
 28879  		this.refractionRatio = 0.98;
 28880  
 28881  		this.wireframe = false;
 28882  		this.wireframeLinewidth = 1;
 28883  		this.wireframeLinecap = 'round';
 28884  		this.wireframeLinejoin = 'round';
 28885  
 28886  		this.skinning = false;
 28887  		this.morphTargets = false;
 28888  		this.morphNormals = false;
 28889  
 28890  		this.setValues( parameters );
 28891  
 28892  	}
 28893  
 28894  	MeshLambertMaterial.prototype = Object.create( Material.prototype );
 28895  	MeshLambertMaterial.prototype.constructor = MeshLambertMaterial;
 28896  
 28897  	MeshLambertMaterial.prototype.isMeshLambertMaterial = true;
 28898  
 28899  	MeshLambertMaterial.prototype.copy = function ( source ) {
 28900  
 28901  		Material.prototype.copy.call( this, source );
 28902  
 28903  		this.color.copy( source.color );
 28904  
 28905  		this.map = source.map;
 28906  
 28907  		this.lightMap = source.lightMap;
 28908  		this.lightMapIntensity = source.lightMapIntensity;
 28909  
 28910  		this.aoMap = source.aoMap;
 28911  		this.aoMapIntensity = source.aoMapIntensity;
 28912  
 28913  		this.emissive.copy( source.emissive );
 28914  		this.emissiveMap = source.emissiveMap;
 28915  		this.emissiveIntensity = source.emissiveIntensity;
 28916  
 28917  		this.specularMap = source.specularMap;
 28918  
 28919  		this.alphaMap = source.alphaMap;
 28920  
 28921  		this.envMap = source.envMap;
 28922  		this.combine = source.combine;
 28923  		this.reflectivity = source.reflectivity;
 28924  		this.refractionRatio = source.refractionRatio;
 28925  
 28926  		this.wireframe = source.wireframe;
 28927  		this.wireframeLinewidth = source.wireframeLinewidth;
 28928  		this.wireframeLinecap = source.wireframeLinecap;
 28929  		this.wireframeLinejoin = source.wireframeLinejoin;
 28930  
 28931  		this.skinning = source.skinning;
 28932  		this.morphTargets = source.morphTargets;
 28933  		this.morphNormals = source.morphNormals;
 28934  
 28935  		return this;
 28936  
 28937  	};
 28938  
 28939  	/**
 28940  	 * @author alteredq / http://alteredqualia.com/
 28941  	 *
 28942  	 * parameters = {
 28943  	 *  color: <hex>,
 28944  	 *  opacity: <float>,
 28945  	 *
 28946  	 *  linewidth: <float>,
 28947  	 *
 28948  	 *  scale: <float>,
 28949  	 *  dashSize: <float>,
 28950  	 *  gapSize: <float>
 28951  	 * }
 28952  	 */
 28953  
 28954  	function LineDashedMaterial( parameters ) {
 28955  
 28956  		Material.call( this );
 28957  
 28958  		this.type = 'LineDashedMaterial';
 28959  
 28960  		this.color = new Color( 0xffffff );
 28961  
 28962  		this.linewidth = 1;
 28963  
 28964  		this.scale = 1;
 28965  		this.dashSize = 3;
 28966  		this.gapSize = 1;
 28967  
 28968  		this.lights = false;
 28969  
 28970  		this.setValues( parameters );
 28971  
 28972  	}
 28973  
 28974  	LineDashedMaterial.prototype = Object.create( Material.prototype );
 28975  	LineDashedMaterial.prototype.constructor = LineDashedMaterial;
 28976  
 28977  	LineDashedMaterial.prototype.isLineDashedMaterial = true;
 28978  
 28979  	LineDashedMaterial.prototype.copy = function ( source ) {
 28980  
 28981  		Material.prototype.copy.call( this, source );
 28982  
 28983  		this.color.copy( source.color );
 28984  
 28985  		this.linewidth = source.linewidth;
 28986  
 28987  		this.scale = source.scale;
 28988  		this.dashSize = source.dashSize;
 28989  		this.gapSize = source.gapSize;
 28990  
 28991  		return this;
 28992  
 28993  	};
 28994  
 28995  
 28996  
 28997  	var Materials = Object.freeze({
 28998  		ShadowMaterial: ShadowMaterial,
 28999  		SpriteMaterial: SpriteMaterial,
 29000  		RawShaderMaterial: RawShaderMaterial,
 29001  		ShaderMaterial: ShaderMaterial,
 29002  		PointsMaterial: PointsMaterial,
 29003  		MultiMaterial: MultiMaterial,
 29004  		MeshPhysicalMaterial: MeshPhysicalMaterial,
 29005  		MeshStandardMaterial: MeshStandardMaterial,
 29006  		MeshPhongMaterial: MeshPhongMaterial,
 29007  		MeshToonMaterial: MeshToonMaterial,
 29008  		MeshNormalMaterial: MeshNormalMaterial,
 29009  		MeshLambertMaterial: MeshLambertMaterial,
 29010  		MeshDepthMaterial: MeshDepthMaterial,
 29011  		MeshBasicMaterial: MeshBasicMaterial,
 29012  		LineDashedMaterial: LineDashedMaterial,
 29013  		LineBasicMaterial: LineBasicMaterial,
 29014  		Material: Material
 29015  	});
 29016  
 29017  	/**
 29018  	 * @author mrdoob / http://mrdoob.com/
 29019  	 */
 29020  
 29021  	var Cache = {
 29022  
 29023  		enabled: false,
 29024  
 29025  		files: {},
 29026  
 29027  		add: function ( key, file ) {
 29028  
 29029  			if ( this.enabled === false ) return;
 29030  
 29031  			// console.log( 'THREE.Cache', 'Adding key:', key );
 29032  
 29033  			this.files[ key ] = file;
 29034  
 29035  		},
 29036  
 29037  		get: function ( key ) {
 29038  
 29039  			if ( this.enabled === false ) return;
 29040  
 29041  			// console.log( 'THREE.Cache', 'Checking key:', key );
 29042  
 29043  			return this.files[ key ];
 29044  
 29045  		},
 29046  
 29047  		remove: function ( key ) {
 29048  
 29049  			delete this.files[ key ];
 29050  
 29051  		},
 29052  
 29053  		clear: function () {
 29054  
 29055  			this.files = {};
 29056  
 29057  		}
 29058  
 29059  	};
 29060  
 29061  	/**
 29062  	 * @author mrdoob / http://mrdoob.com/
 29063  	 */
 29064  
 29065  	function LoadingManager( onLoad, onProgress, onError ) {
 29066  
 29067  		var scope = this;
 29068  
 29069  		var isLoading = false, itemsLoaded = 0, itemsTotal = 0;
 29070  
 29071  		this.onStart = undefined;
 29072  		this.onLoad = onLoad;
 29073  		this.onProgress = onProgress;
 29074  		this.onError = onError;
 29075  
 29076  		this.itemStart = function ( url ) {
 29077  
 29078  			itemsTotal ++;
 29079  
 29080  			if ( isLoading === false ) {
 29081  
 29082  				if ( scope.onStart !== undefined ) {
 29083  
 29084  					scope.onStart( url, itemsLoaded, itemsTotal );
 29085  
 29086  				}
 29087  
 29088  			}
 29089  
 29090  			isLoading = true;
 29091  
 29092  		};
 29093  
 29094  		this.itemEnd = function ( url ) {
 29095  
 29096  			itemsLoaded ++;
 29097  
 29098  			if ( scope.onProgress !== undefined ) {
 29099  
 29100  				scope.onProgress( url, itemsLoaded, itemsTotal );
 29101  
 29102  			}
 29103  
 29104  			if ( itemsLoaded === itemsTotal ) {
 29105  
 29106  				isLoading = false;
 29107  
 29108  				if ( scope.onLoad !== undefined ) {
 29109  
 29110  					scope.onLoad();
 29111  
 29112  				}
 29113  
 29114  			}
 29115  
 29116  		};
 29117  
 29118  		this.itemError = function ( url ) {
 29119  
 29120  			if ( scope.onError !== undefined ) {
 29121  
 29122  				scope.onError( url );
 29123  
 29124  			}
 29125  
 29126  		};
 29127  
 29128  	}
 29129  
 29130  	var DefaultLoadingManager = new LoadingManager();
 29131  
 29132  	/**
 29133  	 * @author mrdoob / http://mrdoob.com/
 29134  	 */
 29135  
 29136  	function FileLoader( manager ) {
 29137  
 29138  		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
 29139  
 29140  	}
 29141  
 29142  	Object.assign( FileLoader.prototype, {
 29143  
 29144  		load: function ( url, onLoad, onProgress, onError ) {
 29145  
 29146  			if ( url === undefined ) url = '';
 29147  
 29148  			if ( this.path !== undefined ) url = this.path + url;
 29149  
 29150  			var scope = this;
 29151  
 29152  			var cached = Cache.get( url );
 29153  
 29154  			if ( cached !== undefined ) {
 29155  
 29156  				scope.manager.itemStart( url );
 29157  
 29158  				setTimeout( function () {
 29159  
 29160  					if ( onLoad ) onLoad( cached );
 29161  
 29162  					scope.manager.itemEnd( url );
 29163  
 29164  				}, 0 );
 29165  
 29166  				return cached;
 29167  
 29168  			}
 29169  
 29170  			// Check for data: URI
 29171  			var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
 29172  			var dataUriRegexResult = url.match( dataUriRegex );
 29173  
 29174  			// Safari can not handle Data URIs through XMLHttpRequest so process manually
 29175  			if ( dataUriRegexResult ) {
 29176  
 29177  				var mimeType = dataUriRegexResult[ 1 ];
 29178  				var isBase64 = !! dataUriRegexResult[ 2 ];
 29179  				var data = dataUriRegexResult[ 3 ];
 29180  
 29181  				data = window.decodeURIComponent( data );
 29182  
 29183  				if ( isBase64 ) data = window.atob( data );
 29184  
 29185  				try {
 29186  
 29187  					var response;
 29188  					var responseType = ( this.responseType || '' ).toLowerCase();
 29189  
 29190  					switch ( responseType ) {
 29191  
 29192  						case 'arraybuffer':
 29193  						case 'blob':
 29194  
 29195  						 	response = new ArrayBuffer( data.length );
 29196  
 29197  							var view = new Uint8Array( response );
 29198  
 29199  							for ( var i = 0; i < data.length; i ++ ) {
 29200  
 29201  								view[ i ] = data.charCodeAt( i );
 29202  
 29203  							}
 29204  
 29205  							if ( responseType === 'blob' ) {
 29206  
 29207  								response = new Blob( [ response ], { type: mimeType } );
 29208  
 29209  							}
 29210  
 29211  							break;
 29212  
 29213  						case 'document':
 29214  
 29215  							var parser = new DOMParser();
 29216  							response = parser.parseFromString( data, mimeType );
 29217  
 29218  							break;
 29219  
 29220  						case 'json':
 29221  
 29222  							response = JSON.parse( data );
 29223  
 29224  							break;
 29225  
 29226  						default: // 'text' or other
 29227  
 29228  							response = data;
 29229  
 29230  							break;
 29231  
 29232  					}
 29233  
 29234  					// Wait for next browser tick
 29235  					window.setTimeout( function () {
 29236  
 29237  						if ( onLoad ) onLoad( response );
 29238  
 29239  						scope.manager.itemEnd( url );
 29240  
 29241  					}, 0 );
 29242  
 29243  				} catch ( error ) {
 29244  
 29245  					// Wait for next browser tick
 29246  					window.setTimeout( function () {
 29247  
 29248  						if ( onError ) onError( error );
 29249  
 29250  						scope.manager.itemError( url );
 29251  
 29252  					}, 0 );
 29253  
 29254  				}
 29255  
 29256  			} else {
 29257  
 29258  				var request = new XMLHttpRequest();
 29259  				request.open( 'GET', url, true );
 29260  
 29261  				request.addEventListener( 'load', function ( event ) {
 29262  
 29263  					var response = event.target.response;
 29264  
 29265  					Cache.add( url, response );
 29266  
 29267  					if ( this.status === 200 ) {
 29268  
 29269  						if ( onLoad ) onLoad( response );
 29270  
 29271  						scope.manager.itemEnd( url );
 29272  
 29273  					} else if ( this.status === 0 ) {
 29274  
 29275  						// Some browsers return HTTP Status 0 when using non-http protocol
 29276  						// e.g. 'file://' or 'data://'. Handle as success.
 29277  
 29278  						console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
 29279  
 29280  						if ( onLoad ) onLoad( response );
 29281  
 29282  						scope.manager.itemEnd( url );
 29283  
 29284  					} else {
 29285  
 29286  						if ( onError ) onError( event );
 29287  
 29288  						scope.manager.itemError( url );
 29289  
 29290  					}
 29291  
 29292  				}, false );
 29293  
 29294  				if ( onProgress !== undefined ) {
 29295  
 29296  					request.addEventListener( 'progress', function ( event ) {
 29297  
 29298  						onProgress( event );
 29299  
 29300  					}, false );
 29301  
 29302  				}
 29303  
 29304  				request.addEventListener( 'error', function ( event ) {
 29305  
 29306  					if ( onError ) onError( event );
 29307  
 29308  					scope.manager.itemError( url );
 29309  
 29310  				}, false );
 29311  
 29312  				if ( this.responseType !== undefined ) request.responseType = this.responseType;
 29313  				if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
 29314  
 29315  				if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );
 29316  
 29317  				request.send( null );
 29318  
 29319  			}
 29320  
 29321  			scope.manager.itemStart( url );
 29322  
 29323  			return request;
 29324  
 29325  		},
 29326  
 29327  		setPath: function ( value ) {
 29328  
 29329  			this.path = value;
 29330  			return this;
 29331  
 29332  		},
 29333  
 29334  		setResponseType: function ( value ) {
 29335  
 29336  			this.responseType = value;
 29337  			return this;
 29338  
 29339  		},
 29340  
 29341  		setWithCredentials: function ( value ) {
 29342  
 29343  			this.withCredentials = value;
 29344  			return this;
 29345  
 29346  		},
 29347  
 29348  		setMimeType: function ( value ) {
 29349  
 29350  			this.mimeType = value;
 29351  			return this;
 29352  
 29353  		}
 29354  
 29355  	} );
 29356  
 29357  	/**
 29358  	 * @author mrdoob / http://mrdoob.com/
 29359  	 *
 29360  	 * Abstract Base class to block based textures loader (dds, pvr, ...)
 29361  	 */
 29362  
 29363  	function CompressedTextureLoader( manager ) {
 29364  
 29365  		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
 29366  
 29367  		// override in sub classes
 29368  		this._parser = null;
 29369  
 29370  	}
 29371  
 29372  	Object.assign( CompressedTextureLoader.prototype, {
 29373  
 29374  		load: function ( url, onLoad, onProgress, onError ) {
 29375  
 29376  			var scope = this;
 29377  
 29378  			var images = [];
 29379  
 29380  			var texture = new CompressedTexture();
 29381  			texture.image = images;
 29382  
 29383  			var loader = new FileLoader( this.manager );
 29384  			loader.setPath( this.path );
 29385  			loader.setResponseType( 'arraybuffer' );
 29386  
 29387  			function loadTexture( i ) {
 29388  
 29389  				loader.load( url[ i ], function ( buffer ) {
 29390  
 29391  					var texDatas = scope._parser( buffer, true );
 29392  
 29393  					images[ i ] = {
 29394  						width: texDatas.width,
 29395  						height: texDatas.height,
 29396  						format: texDatas.format,
 29397  						mipmaps: texDatas.mipmaps
 29398  					};
 29399  
 29400  					loaded += 1;
 29401  
 29402  					if ( loaded === 6 ) {
 29403  
 29404  						if ( texDatas.mipmapCount === 1 )
 29405  							texture.minFilter = LinearFilter;
 29406  
 29407  						texture.format = texDatas.format;
 29408  						texture.needsUpdate = true;
 29409  
 29410  						if ( onLoad ) onLoad( texture );
 29411  
 29412  					}
 29413  
 29414  				}, onProgress, onError );
 29415  
 29416  			}
 29417  
 29418  			if ( Array.isArray( url ) ) {
 29419  
 29420  				var loaded = 0;
 29421  
 29422  				for ( var i = 0, il = url.length; i < il; ++ i ) {
 29423  
 29424  					loadTexture( i );
 29425  
 29426  				}
 29427  
 29428  			} else {
 29429  
 29430  				// compressed cubemap texture stored in a single DDS file
 29431  
 29432  				loader.load( url, function ( buffer ) {
 29433  
 29434  					var texDatas = scope._parser( buffer, true );
 29435  
 29436  					if ( texDatas.isCubemap ) {
 29437  
 29438  						var faces = texDatas.mipmaps.length / texDatas.mipmapCount;
 29439  
 29440  						for ( var f = 0; f < faces; f ++ ) {
 29441  
 29442  							images[ f ] = { mipmaps : [] };
 29443  
 29444  							for ( var i = 0; i < texDatas.mipmapCount; i ++ ) {
 29445  
 29446  								images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );
 29447  								images[ f ].format = texDatas.format;
 29448  								images[ f ].width = texDatas.width;
 29449  								images[ f ].height = texDatas.height;
 29450  
 29451  							}
 29452  
 29453  						}
 29454  
 29455  					} else {
 29456  
 29457  						texture.image.width = texDatas.width;
 29458  						texture.image.height = texDatas.height;
 29459  						texture.mipmaps = texDatas.mipmaps;
 29460  
 29461  					}
 29462  
 29463  					if ( texDatas.mipmapCount === 1 ) {
 29464  
 29465  						texture.minFilter = LinearFilter;
 29466  
 29467  					}
 29468  
 29469  					texture.format = texDatas.format;
 29470  					texture.needsUpdate = true;
 29471  
 29472  					if ( onLoad ) onLoad( texture );
 29473  
 29474  				}, onProgress, onError );
 29475  
 29476  			}
 29477  
 29478  			return texture;
 29479  
 29480  		},
 29481  
 29482  		setPath: function ( value ) {
 29483  
 29484  			this.path = value;
 29485  			return this;
 29486  
 29487  		}
 29488  
 29489  	} );
 29490  
 29491  	/**
 29492  	 * @author Nikos M. / https://github.com/foo123/
 29493  	 *
 29494  	 * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)
 29495  	 */
 29496  
 29497  	function DataTextureLoader( manager ) {
 29498  
 29499  		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
 29500  
 29501  		// override in sub classes
 29502  		this._parser = null;
 29503  
 29504  	}
 29505  
 29506  	Object.assign( DataTextureLoader.prototype, {
 29507  
 29508  		load: function ( url, onLoad, onProgress, onError ) {
 29509  
 29510  			var scope = this;
 29511  
 29512  			var texture = new DataTexture();
 29513  
 29514  			var loader = new FileLoader( this.manager );
 29515  			loader.setResponseType( 'arraybuffer' );
 29516  
 29517  			loader.load( url, function ( buffer ) {
 29518  
 29519  				var texData = scope._parser( buffer );
 29520  
 29521  				if ( ! texData ) return;
 29522  
 29523  				if ( undefined !== texData.image ) {
 29524  
 29525  					texture.image = texData.image;
 29526  
 29527  				} else if ( undefined !== texData.data ) {
 29528  
 29529  					texture.image.width = texData.width;
 29530  					texture.image.height = texData.height;
 29531  					texture.image.data = texData.data;
 29532  
 29533  				}
 29534  
 29535  				texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : ClampToEdgeWrapping;
 29536  				texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : ClampToEdgeWrapping;
 29537  
 29538  				texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : LinearFilter;
 29539  				texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : LinearMipMapLinearFilter;
 29540  
 29541  				texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1;
 29542  
 29543  				if ( undefined !== texData.format ) {
 29544  
 29545  					texture.format = texData.format;
 29546  
 29547  				}
 29548  				if ( undefined !== texData.type ) {
 29549  
 29550  					texture.type = texData.type;
 29551  
 29552  				}
 29553  
 29554  				if ( undefined !== texData.mipmaps ) {
 29555  
 29556  					texture.mipmaps = texData.mipmaps;
 29557  
 29558  				}
 29559  
 29560  				if ( 1 === texData.mipmapCount ) {
 29561  
 29562  					texture.minFilter = LinearFilter;
 29563  
 29564  				}
 29565  
 29566  				texture.needsUpdate = true;
 29567  
 29568  				if ( onLoad ) onLoad( texture, texData );
 29569  
 29570  			}, onProgress, onError );
 29571  
 29572  
 29573  			return texture;
 29574  
 29575  		}
 29576  
 29577  	} );
 29578  
 29579  	/**
 29580  	 * @author mrdoob / http://mrdoob.com/
 29581  	 */
 29582  
 29583  	function ImageLoader( manager ) {
 29584  
 29585  		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
 29586  
 29587  	}
 29588  
 29589  	Object.assign( ImageLoader.prototype, {
 29590  
 29591  		load: function ( url, onLoad, onProgress, onError ) {
 29592  
 29593  			if ( url === undefined ) url = '';
 29594  
 29595  			if ( this.path !== undefined ) url = this.path + url;
 29596  
 29597  			var scope = this;
 29598  
 29599  			var cached = Cache.get( url );
 29600  
 29601  			if ( cached !== undefined ) {
 29602  
 29603  				scope.manager.itemStart( url );
 29604  
 29605  				setTimeout( function () {
 29606  
 29607  					if ( onLoad ) onLoad( cached );
 29608  
 29609  					scope.manager.itemEnd( url );
 29610  
 29611  				}, 0 );
 29612  
 29613  				return cached;
 29614  
 29615  			}
 29616  
 29617  			var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' );
 29618  
 29619  			image.addEventListener( 'load', function () {
 29620  
 29621  				Cache.add( url, this );
 29622  
 29623  				if ( onLoad ) onLoad( this );
 29624  
 29625  				scope.manager.itemEnd( url );
 29626  
 29627  			}, false );
 29628  
 29629  			/*
 29630  			image.addEventListener( 'progress', function ( event ) {
 29631  
 29632  				if ( onProgress ) onProgress( event );
 29633  
 29634  			}, false );
 29635  			*/
 29636  
 29637  			image.addEventListener( 'error', function ( event ) {
 29638  
 29639  				if ( onError ) onError( event );
 29640  
 29641  				scope.manager.itemError( url );
 29642  
 29643  			}, false );
 29644  
 29645  			if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
 29646  
 29647  			scope.manager.itemStart( url );
 29648  
 29649  			image.src = url;
 29650  
 29651  			return image;
 29652  
 29653  		},
 29654  
 29655  		setCrossOrigin: function ( value ) {
 29656  
 29657  			this.crossOrigin = value;
 29658  			return this;
 29659  
 29660  		},
 29661  
 29662  		setPath: function ( value ) {
 29663  
 29664  			this.path = value;
 29665  			return this;
 29666  
 29667  		}
 29668  
 29669  	} );
 29670  
 29671  	/**
 29672  	 * @author mrdoob / http://mrdoob.com/
 29673  	 */
 29674  
 29675  	function CubeTextureLoader( manager ) {
 29676  
 29677  		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
 29678  
 29679  	}
 29680  
 29681  	Object.assign( CubeTextureLoader.prototype, {
 29682  
 29683  		load: function ( urls, onLoad, onProgress, onError ) {
 29684  
 29685  			var texture = new CubeTexture();
 29686  
 29687  			var loader = new ImageLoader( this.manager );
 29688  			loader.setCrossOrigin( this.crossOrigin );
 29689  			loader.setPath( this.path );
 29690  
 29691  			var loaded = 0;
 29692  
 29693  			function loadTexture( i ) {
 29694  
 29695  				loader.load( urls[ i ], function ( image ) {
 29696  
 29697  					texture.images[ i ] = image;
 29698  
 29699  					loaded ++;
 29700  
 29701  					if ( loaded === 6 ) {
 29702  
 29703  						texture.needsUpdate = true;
 29704  
 29705  						if ( onLoad ) onLoad( texture );
 29706  
 29707  					}
 29708  
 29709  				}, undefined, onError );
 29710  
 29711  			}
 29712  
 29713  			for ( var i = 0; i < urls.length; ++ i ) {
 29714  
 29715  				loadTexture( i );
 29716  
 29717  			}
 29718  
 29719  			return texture;
 29720  
 29721  		},
 29722  
 29723  		setCrossOrigin: function ( value ) {
 29724  
 29725  			this.crossOrigin = value;
 29726  			return this;
 29727  
 29728  		},
 29729  
 29730  		setPath: function ( value ) {
 29731  
 29732  			this.path = value;
 29733  			return this;
 29734  
 29735  		}
 29736  
 29737  	} );
 29738  
 29739  	/**
 29740  	 * @author mrdoob / http://mrdoob.com/
 29741  	 */
 29742  
 29743  	function TextureLoader( manager ) {
 29744  
 29745  		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
 29746  
 29747  	}
 29748  
 29749  	Object.assign( TextureLoader.prototype, {
 29750  
 29751  		load: function ( url, onLoad, onProgress, onError ) {
 29752  
 29753  			var texture = new Texture();
 29754  
 29755  			var loader = new ImageLoader( this.manager );
 29756  			loader.setCrossOrigin( this.crossOrigin );
 29757  			loader.setPath( this.path );
 29758  			loader.load( url, function ( image ) {
 29759  
 29760  				// JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB.
 29761  				var isJPEG = url.search( /\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0;
 29762  
 29763  				texture.format = isJPEG ? RGBFormat : RGBAFormat;
 29764  				texture.image = image;
 29765  				texture.needsUpdate = true;
 29766  
 29767  				if ( onLoad !== undefined ) {
 29768  
 29769  					onLoad( texture );
 29770  
 29771  				}
 29772  
 29773  			}, onProgress, onError );
 29774  
 29775  			return texture;
 29776  
 29777  		},
 29778  
 29779  		setCrossOrigin: function ( value ) {
 29780  
 29781  			this.crossOrigin = value;
 29782  			return this;
 29783  
 29784  		},
 29785  
 29786  		setPath: function ( value ) {
 29787  
 29788  			this.path = value;
 29789  			return this;
 29790  
 29791  		}
 29792  
 29793  	} );
 29794  
 29795  	/**
 29796  	 * @author mrdoob / http://mrdoob.com/
 29797  	 * @author alteredq / http://alteredqualia.com/
 29798  	 */
 29799  
 29800  	function Light( color, intensity ) {
 29801  
 29802  		Object3D.call( this );
 29803  
 29804  		this.type = 'Light';
 29805  
 29806  		this.color = new Color( color );
 29807  		this.intensity = intensity !== undefined ? intensity : 1;
 29808  
 29809  		this.receiveShadow = undefined;
 29810  
 29811  	}
 29812  
 29813  	Light.prototype = Object.assign( Object.create( Object3D.prototype ), {
 29814  
 29815  		constructor: Light,
 29816  
 29817  		isLight: true,
 29818  
 29819  		copy: function ( source ) {
 29820  
 29821  			Object3D.prototype.copy.call( this, source );
 29822  
 29823  			this.color.copy( source.color );
 29824  			this.intensity = source.intensity;
 29825  
 29826  			return this;
 29827  
 29828  		},
 29829  
 29830  		toJSON: function ( meta ) {
 29831  
 29832  			var data = Object3D.prototype.toJSON.call( this, meta );
 29833  
 29834  			data.object.color = this.color.getHex();
 29835  			data.object.intensity = this.intensity;
 29836  
 29837  			if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();
 29838  
 29839  			if ( this.distance !== undefined ) data.object.distance = this.distance;
 29840  			if ( this.angle !== undefined ) data.object.angle = this.angle;
 29841  			if ( this.decay !== undefined ) data.object.decay = this.decay;
 29842  			if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;
 29843  
 29844  			if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();
 29845  
 29846  			return data;
 29847  
 29848  		}
 29849  
 29850  	} );
 29851  
 29852  	/**
 29853  	 * @author alteredq / http://alteredqualia.com/
 29854  	 */
 29855  
 29856  	function HemisphereLight( skyColor, groundColor, intensity ) {
 29857  
 29858  		Light.call( this, skyColor, intensity );
 29859  
 29860  		this.type = 'HemisphereLight';
 29861  
 29862  		this.castShadow = undefined;
 29863  
 29864  		this.position.copy( Object3D.DefaultUp );
 29865  		this.updateMatrix();
 29866  
 29867  		this.groundColor = new Color( groundColor );
 29868  
 29869  	}
 29870  
 29871  	HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), {
 29872  
 29873  		constructor: HemisphereLight,
 29874  
 29875  		isHemisphereLight: true,
 29876  
 29877  		copy: function ( source ) {
 29878  
 29879  			Light.prototype.copy.call( this, source );
 29880  
 29881  			this.groundColor.copy( source.groundColor );
 29882  
 29883  			return this;
 29884  
 29885  		}
 29886  
 29887  	} );
 29888  
 29889  	/**
 29890  	 * @author mrdoob / http://mrdoob.com/
 29891  	 */
 29892  
 29893  	function LightShadow( camera ) {
 29894  
 29895  		this.camera = camera;
 29896  
 29897  		this.bias = 0;
 29898  		this.radius = 1;
 29899  
 29900  		this.mapSize = new Vector2( 512, 512 );
 29901  
 29902  		this.map = null;
 29903  		this.matrix = new Matrix4();
 29904  
 29905  	}
 29906  
 29907  	Object.assign( LightShadow.prototype, {
 29908  
 29909  		copy: function ( source ) {
 29910  
 29911  			this.camera = source.camera.clone();
 29912  
 29913  			this.bias = source.bias;
 29914  			this.radius = source.radius;
 29915  
 29916  			this.mapSize.copy( source.mapSize );
 29917  
 29918  			return this;
 29919  
 29920  		},
 29921  
 29922  		clone: function () {
 29923  
 29924  			return new this.constructor().copy( this );
 29925  
 29926  		},
 29927  
 29928  		toJSON: function () {
 29929  
 29930  			var object = {};
 29931  
 29932  			if ( this.bias !== 0 ) object.bias = this.bias;
 29933  			if ( this.radius !== 1 ) object.radius = this.radius;
 29934  			if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();
 29935  
 29936  			object.camera = this.camera.toJSON( false ).object;
 29937  			delete object.camera.matrix;
 29938  
 29939  			return object;
 29940  
 29941  		}
 29942  
 29943  	} );
 29944  
 29945  	/**
 29946  	 * @author mrdoob / http://mrdoob.com/
 29947  	 */
 29948  
 29949  	function SpotLightShadow() {
 29950  
 29951  		LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) );
 29952  
 29953  	}
 29954  
 29955  	SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
 29956  
 29957  		constructor: SpotLightShadow,
 29958  
 29959  		isSpotLightShadow: true,
 29960  
 29961  		update: function ( light ) {
 29962  
 29963  			var fov = _Math.RAD2DEG * 2 * light.angle;
 29964  			var aspect = this.mapSize.width / this.mapSize.height;
 29965  			var far = light.distance || 500;
 29966  
 29967  			var camera = this.camera;
 29968  
 29969  			if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {
 29970  
 29971  				camera.fov = fov;
 29972  				camera.aspect = aspect;
 29973  				camera.far = far;
 29974  				camera.updateProjectionMatrix();
 29975  
 29976  			}
 29977  
 29978  		}
 29979  
 29980  	} );
 29981  
 29982  	/**
 29983  	 * @author alteredq / http://alteredqualia.com/
 29984  	 */
 29985  
 29986  	function SpotLight( color, intensity, distance, angle, penumbra, decay ) {
 29987  
 29988  		Light.call( this, color, intensity );
 29989  
 29990  		this.type = 'SpotLight';
 29991  
 29992  		this.position.copy( Object3D.DefaultUp );
 29993  		this.updateMatrix();
 29994  
 29995  		this.target = new Object3D();
 29996  
 29997  		Object.defineProperty( this, 'power', {
 29998  			get: function () {
 29999  				// intensity = power per solid angle.
 30000  				// ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
 30001  				return this.intensity * Math.PI;
 30002  			},
 30003  			set: function ( power ) {
 30004  				// intensity = power per solid angle.
 30005  				// ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
 30006  				this.intensity = power / Math.PI;
 30007  			}
 30008  		} );
 30009  
 30010  		this.distance = ( distance !== undefined ) ? distance : 0;
 30011  		this.angle = ( angle !== undefined ) ? angle : Math.PI / 3;
 30012  		this.penumbra = ( penumbra !== undefined ) ? penumbra : 0;
 30013  		this.decay = ( decay !== undefined ) ? decay : 1;	// for physically correct lights, should be 2.
 30014  
 30015  		this.shadow = new SpotLightShadow();
 30016  
 30017  	}
 30018  
 30019  	SpotLight.prototype = Object.assign( Object.create( Light.prototype ), {
 30020  
 30021  		constructor: SpotLight,
 30022  
 30023  		isSpotLight: true,
 30024  
 30025  		copy: function ( source ) {
 30026  
 30027  			Light.prototype.copy.call( this, source );
 30028  
 30029  			this.distance = source.distance;
 30030  			this.angle = source.angle;
 30031  			this.penumbra = source.penumbra;
 30032  			this.decay = source.decay;
 30033  
 30034  			this.target = source.target.clone();
 30035  
 30036  			this.shadow = source.shadow.clone();
 30037  
 30038  			return this;
 30039  
 30040  		}
 30041  
 30042  	} );
 30043  
 30044  	/**
 30045  	 * @author mrdoob / http://mrdoob.com/
 30046  	 */
 30047  
 30048  
 30049  	function PointLight( color, intensity, distance, decay ) {
 30050  
 30051  		Light.call( this, color, intensity );
 30052  
 30053  		this.type = 'PointLight';
 30054  
 30055  		Object.defineProperty( this, 'power', {
 30056  			get: function () {
 30057  				// intensity = power per solid angle.
 30058  				// ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
 30059  				return this.intensity * 4 * Math.PI;
 30060  
 30061  			},
 30062  			set: function ( power ) {
 30063  				// intensity = power per solid angle.
 30064  				// ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
 30065  				this.intensity = power / ( 4 * Math.PI );
 30066  			}
 30067  		} );
 30068  
 30069  		this.distance = ( distance !== undefined ) ? distance : 0;
 30070  		this.decay = ( decay !== undefined ) ? decay : 1;	// for physically correct lights, should be 2.
 30071  
 30072  		this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) );
 30073  
 30074  	}
 30075  
 30076  	PointLight.prototype = Object.assign( Object.create( Light.prototype ), {
 30077  
 30078  		constructor: PointLight,
 30079  
 30080  		isPointLight: true,
 30081  
 30082  		copy: function ( source ) {
 30083  
 30084  			Light.prototype.copy.call( this, source );
 30085  
 30086  			this.distance = source.distance;
 30087  			this.decay = source.decay;
 30088  
 30089  			this.shadow = source.shadow.clone();
 30090  
 30091  			return this;
 30092  
 30093  		}
 30094  
 30095  	} );
 30096  
 30097  	/**
 30098  	 * @author mrdoob / http://mrdoob.com/
 30099  	 */
 30100  
 30101  	function DirectionalLightShadow( ) {
 30102  
 30103  		LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );
 30104  
 30105  	}
 30106  
 30107  	DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
 30108  
 30109  		constructor: DirectionalLightShadow
 30110  
 30111  	} );
 30112  
 30113  	/**
 30114  	 * @author mrdoob / http://mrdoob.com/
 30115  	 * @author alteredq / http://alteredqualia.com/
 30116  	 */
 30117  
 30118  	function DirectionalLight( color, intensity ) {
 30119  
 30120  		Light.call( this, color, intensity );
 30121  
 30122  		this.type = 'DirectionalLight';
 30123  
 30124  		this.position.copy( Object3D.DefaultUp );
 30125  		this.updateMatrix();
 30126  
 30127  		this.target = new Object3D();
 30128  
 30129  		this.shadow = new DirectionalLightShadow();
 30130  
 30131  	}
 30132  
 30133  	DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), {
 30134  
 30135  		constructor: DirectionalLight,
 30136  
 30137  		isDirectionalLight: true,
 30138  
 30139  		copy: function ( source ) {
 30140  
 30141  			Light.prototype.copy.call( this, source );
 30142  
 30143  			this.target = source.target.clone();
 30144  
 30145  			this.shadow = source.shadow.clone();
 30146  
 30147  			return this;
 30148  
 30149  		}
 30150  
 30151  	} );
 30152  
 30153  	/**
 30154  	 * @author mrdoob / http://mrdoob.com/
 30155  	 */
 30156  
 30157  	function AmbientLight( color, intensity ) {
 30158  
 30159  		Light.call( this, color, intensity );
 30160  
 30161  		this.type = 'AmbientLight';
 30162  
 30163  		this.castShadow = undefined;
 30164  
 30165  	}
 30166  
 30167  	AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), {
 30168  
 30169  		constructor: AmbientLight,
 30170  
 30171  		isAmbientLight: true
 30172  
 30173  	} );
 30174  
 30175  	/**
 30176  	 * @author tschw
 30177  	 * @author Ben Houston / http://clara.io/
 30178  	 * @author David Sarno / http://lighthaus.us/
 30179  	 */
 30180  
 30181  	var AnimationUtils = {
 30182  
 30183  		// same as Array.prototype.slice, but also works on typed arrays
 30184  		arraySlice: function( array, from, to ) {
 30185  
 30186  			if ( AnimationUtils.isTypedArray( array ) ) {
 30187  
 30188  				return new array.constructor( array.subarray( from, to ) );
 30189  
 30190  			}
 30191  
 30192  			return array.slice( from, to );
 30193  
 30194  		},
 30195  
 30196  		// converts an array to a specific type
 30197  		convertArray: function( array, type, forceClone ) {
 30198  
 30199  			if ( ! array || // let 'undefined' and 'null' pass
 30200  					! forceClone && array.constructor === type ) return array;
 30201  
 30202  			if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
 30203  
 30204  				return new type( array ); // create typed array
 30205  
 30206  			}
 30207  
 30208  			return Array.prototype.slice.call( array ); // create Array
 30209  
 30210  		},
 30211  
 30212  		isTypedArray: function( object ) {
 30213  
 30214  			return ArrayBuffer.isView( object ) &&
 30215  					! ( object instanceof DataView );
 30216  
 30217  		},
 30218  
 30219  		// returns an array by which times and values can be sorted
 30220  		getKeyframeOrder: function( times ) {
 30221  
 30222  			function compareTime( i, j ) {
 30223  
 30224  				return times[ i ] - times[ j ];
 30225  
 30226  			}
 30227  
 30228  			var n = times.length;
 30229  			var result = new Array( n );
 30230  			for ( var i = 0; i !== n; ++ i ) result[ i ] = i;
 30231  
 30232  			result.sort( compareTime );
 30233  
 30234  			return result;
 30235  
 30236  		},
 30237  
 30238  		// uses the array previously returned by 'getKeyframeOrder' to sort data
 30239  		sortedArray: function( values, stride, order ) {
 30240  
 30241  			var nValues = values.length;
 30242  			var result = new values.constructor( nValues );
 30243  
 30244  			for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
 30245  
 30246  				var srcOffset = order[ i ] * stride;
 30247  
 30248  				for ( var j = 0; j !== stride; ++ j ) {
 30249  
 30250  					result[ dstOffset ++ ] = values[ srcOffset + j ];
 30251  
 30252  				}
 30253  
 30254  			}
 30255  
 30256  			return result;
 30257  
 30258  		},
 30259  
 30260  		// function for parsing AOS keyframe formats
 30261  		flattenJSON: function( jsonKeys, times, values, valuePropertyName ) {
 30262  
 30263  			var i = 1, key = jsonKeys[ 0 ];
 30264  
 30265  			while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
 30266  
 30267  				key = jsonKeys[ i ++ ];
 30268  
 30269  			}
 30270  
 30271  			if ( key === undefined ) return; // no data
 30272  
 30273  			var value = key[ valuePropertyName ];
 30274  			if ( value === undefined ) return; // no data
 30275  
 30276  			if ( Array.isArray( value ) ) {
 30277  
 30278  				do {
 30279  
 30280  					value = key[ valuePropertyName ];
 30281  
 30282  					if ( value !== undefined ) {
 30283  
 30284  						times.push( key.time );
 30285  						values.push.apply( values, value ); // push all elements
 30286  
 30287  					}
 30288  
 30289  					key = jsonKeys[ i ++ ];
 30290  
 30291  				} while ( key !== undefined );
 30292  
 30293  			} else if ( value.toArray !== undefined ) {
 30294  				// ...assume THREE.Math-ish
 30295  
 30296  				do {
 30297  
 30298  					value = key[ valuePropertyName ];
 30299  
 30300  					if ( value !== undefined ) {
 30301  
 30302  						times.push( key.time );
 30303  						value.toArray( values, values.length );
 30304  
 30305  					}
 30306  
 30307  					key = jsonKeys[ i ++ ];
 30308  
 30309  				} while ( key !== undefined );
 30310  
 30311  			} else {
 30312  				// otherwise push as-is
 30313  
 30314  				do {
 30315  
 30316  					value = key[ valuePropertyName ];
 30317  
 30318  					if ( value !== undefined ) {
 30319  
 30320  						times.push( key.time );
 30321  						values.push( value );
 30322  
 30323  					}
 30324  
 30325  					key = jsonKeys[ i ++ ];
 30326  
 30327  				} while ( key !== undefined );
 30328  
 30329  			}
 30330  
 30331  		}
 30332  
 30333  	};
 30334  
 30335  	/**
 30336  	 * Abstract base class of interpolants over parametric samples.
 30337  	 *
 30338  	 * The parameter domain is one dimensional, typically the time or a path
 30339  	 * along a curve defined by the data.
 30340  	 *
 30341  	 * The sample values can have any dimensionality and derived classes may
 30342  	 * apply special interpretations to the data.
 30343  	 *
 30344  	 * This class provides the interval seek in a Template Method, deferring
 30345  	 * the actual interpolation to derived classes.
 30346  	 *
 30347  	 * Time complexity is O(1) for linear access crossing at most two points
 30348  	 * and O(log N) for random access, where N is the number of positions.
 30349  	 *
 30350  	 * References:
 30351  	 *
 30352  	 * 		http://www.oodesign.com/template-method-pattern.html
 30353  	 *
 30354  	 * @author tschw
 30355  	 */
 30356  
 30357  	function Interpolant(
 30358  			parameterPositions, sampleValues, sampleSize, resultBuffer ) {
 30359  
 30360  		this.parameterPositions = parameterPositions;
 30361  		this._cachedIndex = 0;
 30362  
 30363  		this.resultBuffer = resultBuffer !== undefined ?
 30364  				resultBuffer : new sampleValues.constructor( sampleSize );
 30365  		this.sampleValues = sampleValues;
 30366  		this.valueSize = sampleSize;
 30367  
 30368  	}
 30369  
 30370  	Interpolant.prototype = {
 30371  
 30372  		constructor: Interpolant,
 30373  
 30374  		evaluate: function( t ) {
 30375  
 30376  			var pp = this.parameterPositions,
 30377  				i1 = this._cachedIndex,
 30378  
 30379  				t1 = pp[   i1   ],
 30380  				t0 = pp[ i1 - 1 ];
 30381  
 30382  			validate_interval: {
 30383  
 30384  				seek: {
 30385  
 30386  					var right;
 30387  
 30388  					linear_scan: {
 30389  	//- See http://jsperf.com/comparison-to-undefined/3
 30390  	//- slower code:
 30391  	//-
 30392  	//- 				if ( t >= t1 || t1 === undefined ) {
 30393  						forward_scan: if ( ! ( t < t1 ) ) {
 30394  
 30395  							for ( var giveUpAt = i1 + 2; ;) {
 30396  
 30397  								if ( t1 === undefined ) {
 30398  
 30399  									if ( t < t0 ) break forward_scan;
 30400  
 30401  									// after end
 30402  
 30403  									i1 = pp.length;
 30404  									this._cachedIndex = i1;
 30405  									return this.afterEnd_( i1 - 1, t, t0 );
 30406  
 30407  								}
 30408  
 30409  								if ( i1 === giveUpAt ) break; // this loop
 30410  
 30411  								t0 = t1;
 30412  								t1 = pp[ ++ i1 ];
 30413  
 30414  								if ( t < t1 ) {
 30415  
 30416  									// we have arrived at the sought interval
 30417  									break seek;
 30418  
 30419  								}
 30420  
 30421  							}
 30422  
 30423  							// prepare binary search on the right side of the index
 30424  							right = pp.length;
 30425  							break linear_scan;
 30426  
 30427  						}
 30428  
 30429  	//- slower code:
 30430  	//-					if ( t < t0 || t0 === undefined ) {
 30431  						if ( ! ( t >= t0 ) ) {
 30432  
 30433  							// looping?
 30434  
 30435  							var t1global = pp[ 1 ];
 30436  
 30437  							if ( t < t1global ) {
 30438  
 30439  								i1 = 2; // + 1, using the scan for the details
 30440  								t0 = t1global;
 30441  
 30442  							}
 30443  
 30444  							// linear reverse scan
 30445  
 30446  							for ( var giveUpAt = i1 - 2; ;) {
 30447  
 30448  								if ( t0 === undefined ) {
 30449  
 30450  									// before start
 30451  
 30452  									this._cachedIndex = 0;
 30453  									return this.beforeStart_( 0, t, t1 );
 30454  
 30455  								}
 30456  
 30457  								if ( i1 === giveUpAt ) break; // this loop
 30458  
 30459  								t1 = t0;
 30460  								t0 = pp[ -- i1 - 1 ];
 30461  
 30462  								if ( t >= t0 ) {
 30463  
 30464  									// we have arrived at the sought interval
 30465  									break seek;
 30466  
 30467  								}
 30468  
 30469  							}
 30470  
 30471  							// prepare binary search on the left side of the index
 30472  							right = i1;
 30473  							i1 = 0;
 30474  							break linear_scan;
 30475  
 30476  						}
 30477  
 30478  						// the interval is valid
 30479  
 30480  						break validate_interval;
 30481  
 30482  					} // linear scan
 30483  
 30484  					// binary search
 30485  
 30486  					while ( i1 < right ) {
 30487  
 30488  						var mid = ( i1 + right ) >>> 1;
 30489  
 30490  						if ( t < pp[ mid ] ) {
 30491  
 30492  							right = mid;
 30493  
 30494  						} else {
 30495  
 30496  							i1 = mid + 1;
 30497  
 30498  						}
 30499  
 30500  					}
 30501  
 30502  					t1 = pp[   i1   ];
 30503  					t0 = pp[ i1 - 1 ];
 30504  
 30505  					// check boundary cases, again
 30506  
 30507  					if ( t0 === undefined ) {
 30508  
 30509  						this._cachedIndex = 0;
 30510  						return this.beforeStart_( 0, t, t1 );
 30511  
 30512  					}
 30513  
 30514  					if ( t1 === undefined ) {
 30515  
 30516  						i1 = pp.length;
 30517  						this._cachedIndex = i1;
 30518  						return this.afterEnd_( i1 - 1, t0, t );
 30519  
 30520  					}
 30521  
 30522  				} // seek
 30523  
 30524  				this._cachedIndex = i1;
 30525  
 30526  				this.intervalChanged_( i1, t0, t1 );
 30527  
 30528  			} // validate_interval
 30529  
 30530  			return this.interpolate_( i1, t0, t, t1 );
 30531  
 30532  		},
 30533  
 30534  		settings: null, // optional, subclass-specific settings structure
 30535  		// Note: The indirection allows central control of many interpolants.
 30536  
 30537  		// --- Protected interface
 30538  
 30539  		DefaultSettings_: {},
 30540  
 30541  		getSettings_: function() {
 30542  
 30543  			return this.settings || this.DefaultSettings_;
 30544  
 30545  		},
 30546  
 30547  		copySampleValue_: function( index ) {
 30548  
 30549  			// copies a sample value to the result buffer
 30550  
 30551  			var result = this.resultBuffer,
 30552  				values = this.sampleValues,
 30553  				stride = this.valueSize,
 30554  				offset = index * stride;
 30555  
 30556  			for ( var i = 0; i !== stride; ++ i ) {
 30557  
 30558  				result[ i ] = values[ offset + i ];
 30559  
 30560  			}
 30561  
 30562  			return result;
 30563  
 30564  		},
 30565  
 30566  		// Template methods for derived classes:
 30567  
 30568  		interpolate_: function( i1, t0, t, t1 ) {
 30569  
 30570  			throw new Error( "call to abstract method" );
 30571  			// implementations shall return this.resultBuffer
 30572  
 30573  		},
 30574  
 30575  		intervalChanged_: function( i1, t0, t1 ) {
 30576  
 30577  			// empty
 30578  
 30579  		}
 30580  
 30581  	};
 30582  
 30583  	Object.assign( Interpolant.prototype, {
 30584  
 30585  		beforeStart_: //( 0, t, t0 ), returns this.resultBuffer
 30586  			Interpolant.prototype.copySampleValue_,
 30587  
 30588  		afterEnd_: //( N-1, tN-1, t ), returns this.resultBuffer
 30589  			Interpolant.prototype.copySampleValue_
 30590  
 30591  	} );
 30592  
 30593  	/**
 30594  	 * Fast and simple cubic spline interpolant.
 30595  	 *
 30596  	 * It was derived from a Hermitian construction setting the first derivative
 30597  	 * at each sample position to the linear slope between neighboring positions
 30598  	 * over their parameter interval.
 30599  	 *
 30600  	 * @author tschw
 30601  	 */
 30602  
 30603  	function CubicInterpolant(
 30604  			parameterPositions, sampleValues, sampleSize, resultBuffer ) {
 30605  
 30606  		Interpolant.call(
 30607  				this, parameterPositions, sampleValues, sampleSize, resultBuffer );
 30608  
 30609  		this._weightPrev = -0;
 30610  		this._offsetPrev = -0;
 30611  		this._weightNext = -0;
 30612  		this._offsetNext = -0;
 30613  
 30614  	}
 30615  
 30616  	CubicInterpolant.prototype =
 30617  			Object.assign( Object.create( Interpolant.prototype ), {
 30618  
 30619  		constructor: CubicInterpolant,
 30620  
 30621  		DefaultSettings_: {
 30622  
 30623  			endingStart: 	ZeroCurvatureEnding,
 30624  			endingEnd:		ZeroCurvatureEnding
 30625  
 30626  		},
 30627  
 30628  		intervalChanged_: function( i1, t0, t1 ) {
 30629  
 30630  			var pp = this.parameterPositions,
 30631  				iPrev = i1 - 2,
 30632  				iNext = i1 + 1,
 30633  
 30634  				tPrev = pp[ iPrev ],
 30635  				tNext = pp[ iNext ];
 30636  
 30637  			if ( tPrev === undefined ) {
 30638  
 30639  				switch ( this.getSettings_().endingStart ) {
 30640  
 30641  					case ZeroSlopeEnding:
 30642  
 30643  						// f'(t0) = 0
 30644  						iPrev = i1;
 30645  						tPrev = 2 * t0 - t1;
 30646  
 30647  						break;
 30648  
 30649  					case WrapAroundEnding:
 30650  
 30651  						// use the other end of the curve
 30652  						iPrev = pp.length - 2;
 30653  						tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
 30654  
 30655  						break;
 30656  
 30657  					default: // ZeroCurvatureEnding
 30658  
 30659  						// f''(t0) = 0 a.k.a. Natural Spline
 30660  						iPrev = i1;
 30661  						tPrev = t1;
 30662  
 30663  				}
 30664  
 30665  			}
 30666  
 30667  			if ( tNext === undefined ) {
 30668  
 30669  				switch ( this.getSettings_().endingEnd ) {
 30670  
 30671  					case ZeroSlopeEnding:
 30672  
 30673  						// f'(tN) = 0
 30674  						iNext = i1;
 30675  						tNext = 2 * t1 - t0;
 30676  
 30677  						break;
 30678  
 30679  					case WrapAroundEnding:
 30680  
 30681  						// use the other end of the curve
 30682  						iNext = 1;
 30683  						tNext = t1 + pp[ 1 ] - pp[ 0 ];
 30684  
 30685  						break;
 30686  
 30687  					default: // ZeroCurvatureEnding
 30688  
 30689  						// f''(tN) = 0, a.k.a. Natural Spline
 30690  						iNext = i1 - 1;
 30691  						tNext = t0;
 30692  
 30693  				}
 30694  
 30695  			}
 30696  
 30697  			var halfDt = ( t1 - t0 ) * 0.5,
 30698  				stride = this.valueSize;
 30699  
 30700  			this._weightPrev = halfDt / ( t0 - tPrev );
 30701  			this._weightNext = halfDt / ( tNext - t1 );
 30702  			this._offsetPrev = iPrev * stride;
 30703  			this._offsetNext = iNext * stride;
 30704  
 30705  		},
 30706  
 30707  		interpolate_: function( i1, t0, t, t1 ) {
 30708  
 30709  			var result = this.resultBuffer,
 30710  				values = this.sampleValues,
 30711  				stride = this.valueSize,
 30712  
 30713  				o1 = i1 * stride,		o0 = o1 - stride,
 30714  				oP = this._offsetPrev, 	oN = this._offsetNext,
 30715  				wP = this._weightPrev,	wN = this._weightNext,
 30716  
 30717  				p = ( t - t0 ) / ( t1 - t0 ),
 30718  				pp = p * p,
 30719  				ppp = pp * p;
 30720  
 30721  			// evaluate polynomials
 30722  
 30723  			var sP =     - wP   * ppp   +         2 * wP    * pp    -          wP   * p;
 30724  			var s0 = ( 1 + wP ) * ppp   + (-1.5 - 2 * wP )  * pp    + ( -0.5 + wP ) * p     + 1;
 30725  			var s1 = (-1 - wN ) * ppp   + ( 1.5 +   wN   )  * pp    +    0.5        * p;
 30726  			var sN =       wN   * ppp   -           wN      * pp;
 30727  
 30728  			// combine data linearly
 30729  
 30730  			for ( var i = 0; i !== stride; ++ i ) {
 30731  
 30732  				result[ i ] =
 30733  						sP * values[ oP + i ] +
 30734  						s0 * values[ o0 + i ] +
 30735  						s1 * values[ o1 + i ] +
 30736  						sN * values[ oN + i ];
 30737  
 30738  			}
 30739  
 30740  			return result;
 30741  
 30742  		}
 30743  
 30744  	} );
 30745  
 30746  	/**
 30747  	 * @author tschw
 30748  	 */
 30749  
 30750  	function LinearInterpolant(
 30751  			parameterPositions, sampleValues, sampleSize, resultBuffer ) {
 30752  
 30753  		Interpolant.call(
 30754  				this, parameterPositions, sampleValues, sampleSize, resultBuffer );
 30755  
 30756  	}
 30757  
 30758  	LinearInterpolant.prototype =
 30759  			Object.assign( Object.create( Interpolant.prototype ), {
 30760  
 30761  		constructor: LinearInterpolant,
 30762  
 30763  		interpolate_: function( i1, t0, t, t1 ) {
 30764  
 30765  			var result = this.resultBuffer,
 30766  				values = this.sampleValues,
 30767  				stride = this.valueSize,
 30768  
 30769  				offset1 = i1 * stride,
 30770  				offset0 = offset1 - stride,
 30771  
 30772  				weight1 = ( t - t0 ) / ( t1 - t0 ),
 30773  				weight0 = 1 - weight1;
 30774  
 30775  			for ( var i = 0; i !== stride; ++ i ) {
 30776  
 30777  				result[ i ] =
 30778  						values[ offset0 + i ] * weight0 +
 30779  						values[ offset1 + i ] * weight1;
 30780  
 30781  			}
 30782  
 30783  			return result;
 30784  
 30785  		}
 30786  
 30787  	} );
 30788  
 30789  	/**
 30790  	 *
 30791  	 * Interpolant that evaluates to the sample value at the position preceeding
 30792  	 * the parameter.
 30793  	 *
 30794  	 * @author tschw
 30795  	 */
 30796  
 30797  	function DiscreteInterpolant(
 30798  			parameterPositions, sampleValues, sampleSize, resultBuffer ) {
 30799  
 30800  		Interpolant.call(
 30801  				this, parameterPositions, sampleValues, sampleSize, resultBuffer );
 30802  
 30803  	}
 30804  
 30805  	DiscreteInterpolant.prototype =
 30806  			Object.assign( Object.create( Interpolant.prototype ), {
 30807  
 30808  		constructor: DiscreteInterpolant,
 30809  
 30810  		interpolate_: function( i1, t0, t, t1 ) {
 30811  
 30812  			return this.copySampleValue_( i1 - 1 );
 30813  
 30814  		}
 30815  
 30816  	} );
 30817  
 30818  	var KeyframeTrackPrototype;
 30819  
 30820  	KeyframeTrackPrototype = {
 30821  
 30822  		TimeBufferType: Float32Array,
 30823  		ValueBufferType: Float32Array,
 30824  
 30825  		DefaultInterpolation: InterpolateLinear,
 30826  
 30827  		InterpolantFactoryMethodDiscrete: function ( result ) {
 30828  
 30829  			return new DiscreteInterpolant(
 30830  					this.times, this.values, this.getValueSize(), result );
 30831  
 30832  		},
 30833  
 30834  		InterpolantFactoryMethodLinear: function ( result ) {
 30835  
 30836  			return new LinearInterpolant(
 30837  					this.times, this.values, this.getValueSize(), result );
 30838  
 30839  		},
 30840  
 30841  		InterpolantFactoryMethodSmooth: function ( result ) {
 30842  
 30843  			return new CubicInterpolant(
 30844  					this.times, this.values, this.getValueSize(), result );
 30845  
 30846  		},
 30847  
 30848  		setInterpolation: function ( interpolation ) {
 30849  
 30850  			var factoryMethod;
 30851  
 30852  			switch ( interpolation ) {
 30853  
 30854  				case InterpolateDiscrete:
 30855  
 30856  					factoryMethod = this.InterpolantFactoryMethodDiscrete;
 30857  
 30858  					break;
 30859  
 30860  				case InterpolateLinear:
 30861  
 30862  					factoryMethod = this.InterpolantFactoryMethodLinear;
 30863  
 30864  					break;
 30865  
 30866  				case InterpolateSmooth:
 30867  
 30868  					factoryMethod = this.InterpolantFactoryMethodSmooth;
 30869  
 30870  					break;
 30871  
 30872  			}
 30873  
 30874  			if ( factoryMethod === undefined ) {
 30875  
 30876  				var message = "unsupported interpolation for " +
 30877  						this.ValueTypeName + " keyframe track named " + this.name;
 30878  
 30879  				if ( this.createInterpolant === undefined ) {
 30880  
 30881  					// fall back to default, unless the default itself is messed up
 30882  					if ( interpolation !== this.DefaultInterpolation ) {
 30883  
 30884  						this.setInterpolation( this.DefaultInterpolation );
 30885  
 30886  					} else {
 30887  
 30888  						throw new Error( message ); // fatal, in this case
 30889  
 30890  					}
 30891  
 30892  				}
 30893  
 30894  				console.warn( message );
 30895  				return;
 30896  
 30897  			}
 30898  
 30899  			this.createInterpolant = factoryMethod;
 30900  
 30901  		},
 30902  
 30903  		getInterpolation: function () {
 30904  
 30905  			switch ( this.createInterpolant ) {
 30906  
 30907  				case this.InterpolantFactoryMethodDiscrete:
 30908  
 30909  					return InterpolateDiscrete;
 30910  
 30911  				case this.InterpolantFactoryMethodLinear:
 30912  
 30913  					return InterpolateLinear;
 30914  
 30915  				case this.InterpolantFactoryMethodSmooth:
 30916  
 30917  					return InterpolateSmooth;
 30918  
 30919  			}
 30920  
 30921  		},
 30922  
 30923  		getValueSize: function () {
 30924  
 30925  			return this.values.length / this.times.length;
 30926  
 30927  		},
 30928  
 30929  		// move all keyframes either forwards or backwards in time
 30930  		shift: function ( timeOffset ) {
 30931  
 30932  			if ( timeOffset !== 0.0 ) {
 30933  
 30934  				var times = this.times;
 30935  
 30936  				for ( var i = 0, n = times.length; i !== n; ++ i ) {
 30937  
 30938  					times[ i ] += timeOffset;
 30939  
 30940  				}
 30941  
 30942  			}
 30943  
 30944  			return this;
 30945  
 30946  		},
 30947  
 30948  		// scale all keyframe times by a factor (useful for frame <-> seconds conversions)
 30949  		scale: function ( timeScale ) {
 30950  
 30951  			if ( timeScale !== 1.0 ) {
 30952  
 30953  				var times = this.times;
 30954  
 30955  				for ( var i = 0, n = times.length; i !== n; ++ i ) {
 30956  
 30957  					times[ i ] *= timeScale;
 30958  
 30959  				}
 30960  
 30961  			}
 30962  
 30963  			return this;
 30964  
 30965  		},
 30966  
 30967  		// removes keyframes before and after animation without changing any values within the range [startTime, endTime].
 30968  		// IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
 30969  		trim: function ( startTime, endTime ) {
 30970  
 30971  			var times = this.times,
 30972  				nKeys = times.length,
 30973  				from = 0,
 30974  				to = nKeys - 1;
 30975  
 30976  			while ( from !== nKeys && times[ from ] < startTime ) ++ from;
 30977  			while ( to !== - 1 && times[ to ] > endTime ) -- to;
 30978  
 30979  			++ to; // inclusive -> exclusive bound
 30980  
 30981  			if ( from !== 0 || to !== nKeys ) {
 30982  
 30983  				// empty tracks are forbidden, so keep at least one keyframe
 30984  				if ( from >= to ) to = Math.max( to, 1 ), from = to - 1;
 30985  
 30986  				var stride = this.getValueSize();
 30987  				this.times = AnimationUtils.arraySlice( times, from, to );
 30988  				this.values = AnimationUtils.
 30989  						arraySlice( this.values, from * stride, to * stride );
 30990  
 30991  			}
 30992  
 30993  			return this;
 30994  
 30995  		},
 30996  
 30997  		// ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
 30998  		validate: function () {
 30999  
 31000  			var valid = true;
 31001  
 31002  			var valueSize = this.getValueSize();
 31003  			if ( valueSize - Math.floor( valueSize ) !== 0 ) {
 31004  
 31005  				console.error( "invalid value size in track", this );
 31006  				valid = false;
 31007  
 31008  			}
 31009  
 31010  			var times = this.times,
 31011  				values = this.values,
 31012  
 31013  				nKeys = times.length;
 31014  
 31015  			if ( nKeys === 0 ) {
 31016  
 31017  				console.error( "track is empty", this );
 31018  				valid = false;
 31019  
 31020  			}
 31021  
 31022  			var prevTime = null;
 31023  
 31024  			for ( var i = 0; i !== nKeys; i ++ ) {
 31025  
 31026  				var currTime = times[ i ];
 31027  
 31028  				if ( typeof currTime === 'number' && isNaN( currTime ) ) {
 31029  
 31030  					console.error( "time is not a valid number", this, i, currTime );
 31031  					valid = false;
 31032  					break;
 31033  
 31034  				}
 31035  
 31036  				if ( prevTime !== null && prevTime > currTime ) {
 31037  
 31038  					console.error( "out of order keys", this, i, currTime, prevTime );
 31039  					valid = false;
 31040  					break;
 31041  
 31042  				}
 31043  
 31044  				prevTime = currTime;
 31045  
 31046  			}
 31047  
 31048  			if ( values !== undefined ) {
 31049  
 31050  				if ( AnimationUtils.isTypedArray( values ) ) {
 31051  
 31052  					for ( var i = 0, n = values.length; i !== n; ++ i ) {
 31053  
 31054  						var value = values[ i ];
 31055  
 31056  						if ( isNaN( value ) ) {
 31057  
 31058  							console.error( "value is not a valid number", this, i, value );
 31059  							valid = false;
 31060  							break;
 31061  
 31062  						}
 31063  
 31064  					}
 31065  
 31066  				}
 31067  
 31068  			}
 31069  
 31070  			return valid;
 31071  
 31072  		},
 31073  
 31074  		// removes equivalent sequential keys as common in morph target sequences
 31075  		// (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
 31076  		optimize: function () {
 31077  
 31078  			var times = this.times,
 31079  				values = this.values,
 31080  				stride = this.getValueSize(),
 31081  
 31082  				smoothInterpolation = this.getInterpolation() === InterpolateSmooth,
 31083  
 31084  				writeIndex = 1,
 31085  				lastIndex = times.length - 1;
 31086  
 31087  			for ( var i = 1; i < lastIndex; ++ i ) {
 31088  
 31089  				var keep = false;
 31090  
 31091  				var time = times[ i ];
 31092  				var timeNext = times[ i + 1 ];
 31093  
 31094  				// remove adjacent keyframes scheduled at the same time
 31095  
 31096  				if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) {
 31097  
 31098  					if ( ! smoothInterpolation ) {
 31099  
 31100  						// remove unnecessary keyframes same as their neighbors
 31101  
 31102  						var offset = i * stride,
 31103  							offsetP = offset - stride,
 31104  							offsetN = offset + stride;
 31105  
 31106  						for ( var j = 0; j !== stride; ++ j ) {
 31107  
 31108  							var value = values[ offset + j ];
 31109  
 31110  							if ( value !== values[ offsetP + j ] ||
 31111  									value !== values[ offsetN + j ] ) {
 31112  
 31113  								keep = true;
 31114  								break;
 31115  
 31116  							}
 31117  
 31118  						}
 31119  
 31120  					} else keep = true;
 31121  
 31122  				}
 31123  
 31124  				// in-place compaction
 31125  
 31126  				if ( keep ) {
 31127  
 31128  					if ( i !== writeIndex ) {
 31129  
 31130  						times[ writeIndex ] = times[ i ];
 31131  
 31132  						var readOffset = i * stride,
 31133  							writeOffset = writeIndex * stride;
 31134  
 31135  						for ( var j = 0; j !== stride; ++ j )
 31136  
 31137  							values[ writeOffset + j ] = values[ readOffset + j ];
 31138  
 31139  					}
 31140  
 31141  					++ writeIndex;
 31142  
 31143  				}
 31144  
 31145  			}
 31146  
 31147  			// flush last keyframe (compaction looks ahead)
 31148  
 31149  			if ( lastIndex > 0 ) {
 31150  
 31151  				times[ writeIndex ] = times[ lastIndex ];
 31152  
 31153  				for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j )
 31154  
 31155  					values[ writeOffset + j ] = values[ readOffset + j ];
 31156  
 31157  				++ writeIndex;
 31158  
 31159  			}
 31160  
 31161  			if ( writeIndex !== times.length ) {
 31162  
 31163  				this.times = AnimationUtils.arraySlice( times, 0, writeIndex );
 31164  				this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );
 31165  
 31166  			}
 31167  
 31168  			return this;
 31169  
 31170  		}
 31171  
 31172  	};
 31173  
 31174  	function KeyframeTrackConstructor( name, times, values, interpolation ) {
 31175  
 31176  		if( name === undefined ) throw new Error( "track name is undefined" );
 31177  
 31178  		if( times === undefined || times.length === 0 ) {
 31179  
 31180  			throw new Error( "no keyframes in track named " + name );
 31181  
 31182  		}
 31183  
 31184  		this.name = name;
 31185  
 31186  		this.times = AnimationUtils.convertArray( times, this.TimeBufferType );
 31187  		this.values = AnimationUtils.convertArray( values, this.ValueBufferType );
 31188  
 31189  		this.setInterpolation( interpolation || this.DefaultInterpolation );
 31190  
 31191  		this.validate();
 31192  		this.optimize();
 31193  
 31194  	}
 31195  
 31196  	/**
 31197  	 *
 31198  	 * A Track of vectored keyframe values.
 31199  	 *
 31200  	 *
 31201  	 * @author Ben Houston / http://clara.io/
 31202  	 * @author David Sarno / http://lighthaus.us/
 31203  	 * @author tschw
 31204  	 */
 31205  
 31206  	function VectorKeyframeTrack( name, times, values, interpolation ) {
 31207  
 31208  		KeyframeTrackConstructor.call( this, name, times, values, interpolation );
 31209  
 31210  	}
 31211  
 31212  	VectorKeyframeTrack.prototype =
 31213  			Object.assign( Object.create( KeyframeTrackPrototype ), {
 31214  
 31215  		constructor: VectorKeyframeTrack,
 31216  
 31217  		ValueTypeName: 'vector'
 31218  
 31219  		// ValueBufferType is inherited
 31220  
 31221  		// DefaultInterpolation is inherited
 31222  
 31223  	} );
 31224  
 31225  	/**
 31226  	 * Spherical linear unit quaternion interpolant.
 31227  	 *
 31228  	 * @author tschw
 31229  	 */
 31230  
 31231  	function QuaternionLinearInterpolant(
 31232  			parameterPositions, sampleValues, sampleSize, resultBuffer ) {
 31233  
 31234  		Interpolant.call(
 31235  				this, parameterPositions, sampleValues, sampleSize, resultBuffer );
 31236  
 31237  	}
 31238  
 31239  	QuaternionLinearInterpolant.prototype =
 31240  			Object.assign( Object.create( Interpolant.prototype ), {
 31241  
 31242  		constructor: QuaternionLinearInterpolant,
 31243  
 31244  		interpolate_: function( i1, t0, t, t1 ) {
 31245  
 31246  			var result = this.resultBuffer,
 31247  				values = this.sampleValues,
 31248  				stride = this.valueSize,
 31249  
 31250  				offset = i1 * stride,
 31251  
 31252  				alpha = ( t - t0 ) / ( t1 - t0 );
 31253  
 31254  			for ( var end = offset + stride; offset !== end; offset += 4 ) {
 31255  
 31256  				Quaternion.slerpFlat( result, 0,
 31257  						values, offset - stride, values, offset, alpha );
 31258  
 31259  			}
 31260  
 31261  			return result;
 31262  
 31263  		}
 31264  
 31265  	} );
 31266  
 31267  	/**
 31268  	 *
 31269  	 * A Track of quaternion keyframe values.
 31270  	 *
 31271  	 * @author Ben Houston / http://clara.io/
 31272  	 * @author David Sarno / http://lighthaus.us/
 31273  	 * @author tschw
 31274  	 */
 31275  
 31276  	function QuaternionKeyframeTrack( name, times, values, interpolation ) {
 31277  
 31278  		KeyframeTrackConstructor.call( this, name, times, values, interpolation );
 31279  
 31280  	}
 31281  
 31282  	QuaternionKeyframeTrack.prototype =
 31283  			Object.assign( Object.create( KeyframeTrackPrototype ), {
 31284  
 31285  		constructor: QuaternionKeyframeTrack,
 31286  
 31287  		ValueTypeName: 'quaternion',
 31288  
 31289  		// ValueBufferType is inherited
 31290  
 31291  		DefaultInterpolation: InterpolateLinear,
 31292  
 31293  		InterpolantFactoryMethodLinear: function( result ) {
 31294  
 31295  			return new QuaternionLinearInterpolant(
 31296  					this.times, this.values, this.getValueSize(), result );
 31297  
 31298  		},
 31299  
 31300  		InterpolantFactoryMethodSmooth: undefined // not yet implemented
 31301  
 31302  	} );
 31303  
 31304  	/**
 31305  	 *
 31306  	 * A Track of numeric keyframe values.
 31307  	 *
 31308  	 * @author Ben Houston / http://clara.io/
 31309  	 * @author David Sarno / http://lighthaus.us/
 31310  	 * @author tschw
 31311  	 */
 31312  
 31313  	function NumberKeyframeTrack( name, times, values, interpolation ) {
 31314  
 31315  		KeyframeTrackConstructor.call( this, name, times, values, interpolation );
 31316  
 31317  	}
 31318  
 31319  	NumberKeyframeTrack.prototype =
 31320  			Object.assign( Object.create( KeyframeTrackPrototype ), {
 31321  
 31322  		constructor: NumberKeyframeTrack,
 31323  
 31324  		ValueTypeName: 'number'
 31325  
 31326  		// ValueBufferType is inherited
 31327  
 31328  		// DefaultInterpolation is inherited
 31329  
 31330  	} );
 31331  
 31332  	/**
 31333  	 *
 31334  	 * A Track that interpolates Strings
 31335  	 *
 31336  	 *
 31337  	 * @author Ben Houston / http://clara.io/
 31338  	 * @author David Sarno / http://lighthaus.us/
 31339  	 * @author tschw
 31340  	 */
 31341  
 31342  	function StringKeyframeTrack( name, times, values, interpolation ) {
 31343  
 31344  		KeyframeTrackConstructor.call( this, name, times, values, interpolation );
 31345  
 31346  	}
 31347  
 31348  	StringKeyframeTrack.prototype =
 31349  			Object.assign( Object.create( KeyframeTrackPrototype ), {
 31350  
 31351  		constructor: StringKeyframeTrack,
 31352  
 31353  		ValueTypeName: 'string',
 31354  		ValueBufferType: Array,
 31355  
 31356  		DefaultInterpolation: InterpolateDiscrete,
 31357  
 31358  		InterpolantFactoryMethodLinear: undefined,
 31359  
 31360  		InterpolantFactoryMethodSmooth: undefined
 31361  
 31362  	} );
 31363  
 31364  	/**
 31365  	 *
 31366  	 * A Track of Boolean keyframe values.
 31367  	 *
 31368  	 *
 31369  	 * @author Ben Houston / http://clara.io/
 31370  	 * @author David Sarno / http://lighthaus.us/
 31371  	 * @author tschw
 31372  	 */
 31373  
 31374  	function BooleanKeyframeTrack( name, times, values ) {
 31375  
 31376  		KeyframeTrackConstructor.call( this, name, times, values );
 31377  
 31378  	}
 31379  
 31380  	BooleanKeyframeTrack.prototype =
 31381  			Object.assign( Object.create( KeyframeTrackPrototype ), {
 31382  
 31383  		constructor: BooleanKeyframeTrack,
 31384  
 31385  		ValueTypeName: 'bool',
 31386  		ValueBufferType: Array,
 31387  
 31388  		DefaultInterpolation: InterpolateDiscrete,
 31389  
 31390  		InterpolantFactoryMethodLinear: undefined,
 31391  		InterpolantFactoryMethodSmooth: undefined
 31392  
 31393  		// Note: Actually this track could have a optimized / compressed
 31394  		// representation of a single value and a custom interpolant that
 31395  		// computes "firstValue ^ isOdd( index )".
 31396  
 31397  	} );
 31398  
 31399  	/**
 31400  	 *
 31401  	 * A Track of keyframe values that represent color.
 31402  	 *
 31403  	 *
 31404  	 * @author Ben Houston / http://clara.io/
 31405  	 * @author David Sarno / http://lighthaus.us/
 31406  	 * @author tschw
 31407  	 */
 31408  
 31409  	function ColorKeyframeTrack( name, times, values, interpolation ) {
 31410  
 31411  		KeyframeTrackConstructor.call( this, name, times, values, interpolation );
 31412  
 31413  	}
 31414  
 31415  	ColorKeyframeTrack.prototype =
 31416  			Object.assign( Object.create( KeyframeTrackPrototype ), {
 31417  
 31418  		constructor: ColorKeyframeTrack,
 31419  
 31420  		ValueTypeName: 'color'
 31421  
 31422  		// ValueBufferType is inherited
 31423  
 31424  		// DefaultInterpolation is inherited
 31425  
 31426  
 31427  		// Note: Very basic implementation and nothing special yet.
 31428  		// However, this is the place for color space parameterization.
 31429  
 31430  	} );
 31431  
 31432  	/**
 31433  	 *
 31434  	 * A timed sequence of keyframes for a specific property.
 31435  	 *
 31436  	 *
 31437  	 * @author Ben Houston / http://clara.io/
 31438  	 * @author David Sarno / http://lighthaus.us/
 31439  	 * @author tschw
 31440  	 */
 31441  
 31442  	function KeyframeTrack( name, times, values, interpolation ) {
 31443  
 31444  		KeyframeTrackConstructor.apply( this, arguments );
 31445  
 31446  	}
 31447  
 31448  	KeyframeTrack.prototype = KeyframeTrackPrototype;
 31449  	KeyframeTrackPrototype.constructor = KeyframeTrack;
 31450  
 31451  	// Static methods:
 31452  
 31453  	Object.assign( KeyframeTrack, {
 31454  
 31455  		// Serialization (in static context, because of constructor invocation
 31456  		// and automatic invocation of .toJSON):
 31457  
 31458  		parse: function( json ) {
 31459  
 31460  			if( json.type === undefined ) {
 31461  
 31462  				throw new Error( "track type undefined, can not parse" );
 31463  
 31464  			}
 31465  
 31466  			var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type );
 31467  
 31468  			if ( json.times === undefined ) {
 31469  
 31470  				var times = [], values = [];
 31471  
 31472  				AnimationUtils.flattenJSON( json.keys, times, values, 'value' );
 31473  
 31474  				json.times = times;
 31475  				json.values = values;
 31476  
 31477  			}
 31478  
 31479  			// derived classes can define a static parse method
 31480  			if ( trackType.parse !== undefined ) {
 31481  
 31482  				return trackType.parse( json );
 31483  
 31484  			} else {
 31485  
 31486  				// by default, we asssume a constructor compatible with the base
 31487  				return new trackType(
 31488  						json.name, json.times, json.values, json.interpolation );
 31489  
 31490  			}
 31491  
 31492  		},
 31493  
 31494  		toJSON: function( track ) {
 31495  
 31496  			var trackType = track.constructor;
 31497  
 31498  			var json;
 31499  
 31500  			// derived classes can define a static toJSON method
 31501  			if ( trackType.toJSON !== undefined ) {
 31502  
 31503  				json = trackType.toJSON( track );
 31504  
 31505  			} else {
 31506  
 31507  				// by default, we assume the data can be serialized as-is
 31508  				json = {
 31509  
 31510  					'name': track.name,
 31511  					'times': AnimationUtils.convertArray( track.times, Array ),
 31512  					'values': AnimationUtils.convertArray( track.values, Array )
 31513  
 31514  				};
 31515  
 31516  				var interpolation = track.getInterpolation();
 31517  
 31518  				if ( interpolation !== track.DefaultInterpolation ) {
 31519  
 31520  					json.interpolation = interpolation;
 31521  
 31522  				}
 31523  
 31524  			}
 31525  
 31526  			json.type = track.ValueTypeName; // mandatory
 31527  
 31528  			return json;
 31529  
 31530  		},
 31531  
 31532  		_getTrackTypeForValueTypeName: function( typeName ) {
 31533  
 31534  			switch( typeName.toLowerCase() ) {
 31535  
 31536  				case "scalar":
 31537  				case "double":
 31538  				case "float":
 31539  				case "number":
 31540  				case "integer":
 31541  
 31542  					return NumberKeyframeTrack;
 31543  
 31544  				case "vector":
 31545  				case "vector2":
 31546  				case "vector3":
 31547  				case "vector4":
 31548  
 31549  					return VectorKeyframeTrack;
 31550  
 31551  				case "color":
 31552  
 31553  					return ColorKeyframeTrack;
 31554  
 31555  				case "quaternion":
 31556  
 31557  					return QuaternionKeyframeTrack;
 31558  
 31559  				case "bool":
 31560  				case "boolean":
 31561  
 31562  					return BooleanKeyframeTrack;
 31563  
 31564  				case "string":
 31565  
 31566  					return StringKeyframeTrack;
 31567  
 31568  			}
 31569  
 31570  			throw new Error( "Unsupported typeName: " + typeName );
 31571  
 31572  		}
 31573  
 31574  	} );
 31575  
 31576  	/**
 31577  	 *
 31578  	 * Reusable set of Tracks that represent an animation.
 31579  	 *
 31580  	 * @author Ben Houston / http://clara.io/
 31581  	 * @author David Sarno / http://lighthaus.us/
 31582  	 */
 31583  
 31584  	function AnimationClip( name, duration, tracks ) {
 31585  
 31586  		this.name = name;
 31587  		this.tracks = tracks;
 31588  		this.duration = ( duration !== undefined ) ? duration : -1;
 31589  
 31590  		this.uuid = _Math.generateUUID();
 31591  
 31592  		// this means it should figure out its duration by scanning the tracks
 31593  		if ( this.duration < 0 ) {
 31594  
 31595  			this.resetDuration();
 31596  
 31597  		}
 31598  
 31599  		this.optimize();
 31600  
 31601  	}
 31602  
 31603  	AnimationClip.prototype = {
 31604  
 31605  		constructor: AnimationClip,
 31606  
 31607  		resetDuration: function() {
 31608  
 31609  			var tracks = this.tracks,
 31610  				duration = 0;
 31611  
 31612  			for ( var i = 0, n = tracks.length; i !== n; ++ i ) {
 31613  
 31614  				var track = this.tracks[ i ];
 31615  
 31616  				duration = Math.max( duration, track.times[ track.times.length - 1 ] );
 31617  
 31618  			}
 31619  
 31620  			this.duration = duration;
 31621  
 31622  		},
 31623  
 31624  		trim: function() {
 31625  
 31626  			for ( var i = 0; i < this.tracks.length; i ++ ) {
 31627  
 31628  				this.tracks[ i ].trim( 0, this.duration );
 31629  
 31630  			}
 31631  
 31632  			return this;
 31633  
 31634  		},
 31635  
 31636  		optimize: function() {
 31637  
 31638  			for ( var i = 0; i < this.tracks.length; i ++ ) {
 31639  
 31640  				this.tracks[ i ].optimize();
 31641  
 31642  			}
 31643  
 31644  			return this;
 31645  
 31646  		}
 31647  
 31648  	};
 31649  
 31650  	// Static methods:
 31651  
 31652  	Object.assign( AnimationClip, {
 31653  
 31654  		parse: function( json ) {
 31655  
 31656  			var tracks = [],
 31657  				jsonTracks = json.tracks,
 31658  				frameTime = 1.0 / ( json.fps || 1.0 );
 31659  
 31660  			for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) {
 31661  
 31662  				tracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) );
 31663  
 31664  			}
 31665  
 31666  			return new AnimationClip( json.name, json.duration, tracks );
 31667  
 31668  		},
 31669  
 31670  
 31671  		toJSON: function( clip ) {
 31672  
 31673  			var tracks = [],
 31674  				clipTracks = clip.tracks;
 31675  
 31676  			var json = {
 31677  
 31678  				'name': clip.name,
 31679  				'duration': clip.duration,
 31680  				'tracks': tracks
 31681  
 31682  			};
 31683  
 31684  			for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) {
 31685  
 31686  				tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );
 31687  
 31688  			}
 31689  
 31690  			return json;
 31691  
 31692  		},
 31693  
 31694  
 31695  		CreateFromMorphTargetSequence: function( name, morphTargetSequence, fps, noLoop ) {
 31696  
 31697  			var numMorphTargets = morphTargetSequence.length;
 31698  			var tracks = [];
 31699  
 31700  			for ( var i = 0; i < numMorphTargets; i ++ ) {
 31701  
 31702  				var times = [];
 31703  				var values = [];
 31704  
 31705  				times.push(
 31706  						( i + numMorphTargets - 1 ) % numMorphTargets,
 31707  						i,
 31708  						( i + 1 ) % numMorphTargets );
 31709  
 31710  				values.push( 0, 1, 0 );
 31711  
 31712  				var order = AnimationUtils.getKeyframeOrder( times );
 31713  				times = AnimationUtils.sortedArray( times, 1, order );
 31714  				values = AnimationUtils.sortedArray( values, 1, order );
 31715  
 31716  				// if there is a key at the first frame, duplicate it as the
 31717  				// last frame as well for perfect loop.
 31718  				if ( ! noLoop && times[ 0 ] === 0 ) {
 31719  
 31720  					times.push( numMorphTargets );
 31721  					values.push( values[ 0 ] );
 31722  
 31723  				}
 31724  
 31725  				tracks.push(
 31726  						new NumberKeyframeTrack(
 31727  							'.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',
 31728  							times, values
 31729  						).scale( 1.0 / fps ) );
 31730  			}
 31731  
 31732  			return new AnimationClip( name, -1, tracks );
 31733  
 31734  		},
 31735  
 31736  		findByName: function( objectOrClipArray, name ) {
 31737  
 31738  			var clipArray = objectOrClipArray;
 31739  
 31740  			if ( ! Array.isArray( objectOrClipArray ) ) {
 31741  
 31742  				var o = objectOrClipArray;
 31743  				clipArray = o.geometry && o.geometry.animations || o.animations;
 31744  
 31745  			}
 31746  
 31747  			for ( var i = 0; i < clipArray.length; i ++ ) {
 31748  
 31749  				if ( clipArray[ i ].name === name ) {
 31750  
 31751  					return clipArray[ i ];
 31752  
 31753  				}
 31754  			}
 31755  
 31756  			return null;
 31757  
 31758  		},
 31759  
 31760  		CreateClipsFromMorphTargetSequences: function( morphTargets, fps, noLoop ) {
 31761  
 31762  			var animationToMorphTargets = {};
 31763  
 31764  			// tested with https://regex101.com/ on trick sequences
 31765  			// such flamingo_flyA_003, flamingo_run1_003, crdeath0059
 31766  			var pattern = /^([\w-]*?)([\d]+)$/;
 31767  
 31768  			// sort morph target names into animation groups based
 31769  			// patterns like Walk_001, Walk_002, Run_001, Run_002
 31770  			for ( var i = 0, il = morphTargets.length; i < il; i ++ ) {
 31771  
 31772  				var morphTarget = morphTargets[ i ];
 31773  				var parts = morphTarget.name.match( pattern );
 31774  
 31775  				if ( parts && parts.length > 1 ) {
 31776  
 31777  					var name = parts[ 1 ];
 31778  
 31779  					var animationMorphTargets = animationToMorphTargets[ name ];
 31780  					if ( ! animationMorphTargets ) {
 31781  
 31782  						animationToMorphTargets[ name ] = animationMorphTargets = [];
 31783  
 31784  					}
 31785  
 31786  					animationMorphTargets.push( morphTarget );
 31787  
 31788  				}
 31789  
 31790  			}
 31791  
 31792  			var clips = [];
 31793  
 31794  			for ( var name in animationToMorphTargets ) {
 31795  
 31796  				clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );
 31797  
 31798  			}
 31799  
 31800  			return clips;
 31801  
 31802  		},
 31803  
 31804  		// parse the animation.hierarchy format
 31805  		parseAnimation: function( animation, bones ) {
 31806  
 31807  			if ( ! animation ) {
 31808  
 31809  				console.error( "  no animation in JSONLoader data" );
 31810  				return null;
 31811  
 31812  			}
 31813  
 31814  			var addNonemptyTrack = function(
 31815  					trackType, trackName, animationKeys, propertyName, destTracks ) {
 31816  
 31817  				// only return track if there are actually keys.
 31818  				if ( animationKeys.length !== 0 ) {
 31819  
 31820  					var times = [];
 31821  					var values = [];
 31822  
 31823  					AnimationUtils.flattenJSON(
 31824  							animationKeys, times, values, propertyName );
 31825  
 31826  					// empty keys are filtered out, so check again
 31827  					if ( times.length !== 0 ) {
 31828  
 31829  						destTracks.push( new trackType( trackName, times, values ) );
 31830  
 31831  					}
 31832  
 31833  				}
 31834  
 31835  			};
 31836  
 31837  			var tracks = [];
 31838  
 31839  			var clipName = animation.name || 'default';
 31840  			// automatic length determination in AnimationClip.
 31841  			var duration = animation.length || -1;
 31842  			var fps = animation.fps || 30;
 31843  
 31844  			var hierarchyTracks = animation.hierarchy || [];
 31845  
 31846  			for ( var h = 0; h < hierarchyTracks.length; h ++ ) {
 31847  
 31848  				var animationKeys = hierarchyTracks[ h ].keys;
 31849  
 31850  				// skip empty tracks
 31851  				if ( ! animationKeys || animationKeys.length === 0 ) continue;
 31852  
 31853  				// process morph targets in a way exactly compatible
 31854  				// with AnimationHandler.init( animation )
 31855  				if ( animationKeys[0].morphTargets ) {
 31856  
 31857  					// figure out all morph targets used in this track
 31858  					var morphTargetNames = {};
 31859  					for ( var k = 0; k < animationKeys.length; k ++ ) {
 31860  
 31861  						if ( animationKeys[k].morphTargets ) {
 31862  
 31863  							for ( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) {
 31864  
 31865  								morphTargetNames[ animationKeys[k].morphTargets[m] ] = -1;
 31866  							}
 31867  
 31868  						}
 31869  
 31870  					}
 31871  
 31872  					// create a track for each morph target with all zero
 31873  					// morphTargetInfluences except for the keys in which
 31874  					// the morphTarget is named.
 31875  					for ( var morphTargetName in morphTargetNames ) {
 31876  
 31877  						var times = [];
 31878  						var values = [];
 31879  
 31880  						for ( var m = 0; m !== animationKeys[k].morphTargets.length; ++ m ) {
 31881  
 31882  							var animationKey = animationKeys[k];
 31883  
 31884  							times.push( animationKey.time );
 31885  							values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );
 31886  
 31887  						}
 31888  
 31889  						tracks.push( new NumberKeyframeTrack('.morphTargetInfluence[' + morphTargetName + ']', times, values ) );
 31890  
 31891  					}
 31892  
 31893  					duration = morphTargetNames.length * ( fps || 1.0 );
 31894  
 31895  				} else {
 31896  					// ...assume skeletal animation
 31897  
 31898  					var boneName = '.bones[' + bones[ h ].name + ']';
 31899  
 31900  					addNonemptyTrack(
 31901  							VectorKeyframeTrack, boneName + '.position',
 31902  							animationKeys, 'pos', tracks );
 31903  
 31904  					addNonemptyTrack(
 31905  							QuaternionKeyframeTrack, boneName + '.quaternion',
 31906  							animationKeys, 'rot', tracks );
 31907  
 31908  					addNonemptyTrack(
 31909  							VectorKeyframeTrack, boneName + '.scale',
 31910  							animationKeys, 'scl', tracks );
 31911  
 31912  				}
 31913  
 31914  			}
 31915  
 31916  			if ( tracks.length === 0 ) {
 31917  
 31918  				return null;
 31919  
 31920  			}
 31921  
 31922  			var clip = new AnimationClip( clipName, duration, tracks );
 31923  
 31924  			return clip;
 31925  
 31926  		}
 31927  
 31928  	} );
 31929  
 31930  	/**
 31931  	 * @author mrdoob / http://mrdoob.com/
 31932  	 */
 31933  
 31934  	function MaterialLoader( manager ) {
 31935  
 31936  		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
 31937  		this.textures = {};
 31938  
 31939  	}
 31940  
 31941  	Object.assign( MaterialLoader.prototype, {
 31942  
 31943  		load: function ( url, onLoad, onProgress, onError ) {
 31944  
 31945  			var scope = this;
 31946  
 31947  			var loader = new FileLoader( scope.manager );
 31948  			loader.load( url, function ( text ) {
 31949  
 31950  				onLoad( scope.parse( JSON.parse( text ) ) );
 31951  
 31952  			}, onProgress, onError );
 31953  
 31954  		},
 31955  
 31956  		setTextures: function ( value ) {
 31957  
 31958  			this.textures = value;
 31959  
 31960  		},
 31961  
 31962  		parse: function ( json ) {
 31963  
 31964  			var textures = this.textures;
 31965  
 31966  			function getTexture( name ) {
 31967  
 31968  				if ( textures[ name ] === undefined ) {
 31969  
 31970  					console.warn( 'THREE.MaterialLoader: Undefined texture', name );
 31971  
 31972  				}
 31973  
 31974  				return textures[ name ];
 31975  
 31976  			}
 31977  
 31978  			var material = new Materials[ json.type ]();
 31979  
 31980  			if ( json.uuid !== undefined ) material.uuid = json.uuid;
 31981  			if ( json.name !== undefined ) material.name = json.name;
 31982  			if ( json.color !== undefined ) material.color.setHex( json.color );
 31983  			if ( json.roughness !== undefined ) material.roughness = json.roughness;
 31984  			if ( json.metalness !== undefined ) material.metalness = json.metalness;
 31985  			if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive );
 31986  			if ( json.specular !== undefined ) material.specular.setHex( json.specular );
 31987  			if ( json.shininess !== undefined ) material.shininess = json.shininess;
 31988  			if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat;
 31989  			if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness;
 31990  			if ( json.uniforms !== undefined ) material.uniforms = json.uniforms;
 31991  			if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;
 31992  			if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;
 31993  			if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors;
 31994  			if ( json.fog !== undefined ) material.fog = json.fog;
 31995  			if ( json.shading !== undefined ) material.shading = json.shading;
 31996  			if ( json.blending !== undefined ) material.blending = json.blending;
 31997  			if ( json.side !== undefined ) material.side = json.side;
 31998  			if ( json.opacity !== undefined ) material.opacity = json.opacity;
 31999  			if ( json.transparent !== undefined ) material.transparent = json.transparent;
 32000  			if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;
 32001  			if ( json.depthTest !== undefined ) material.depthTest = json.depthTest;
 32002  			if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;
 32003  			if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;
 32004  			if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
 32005  			if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;
 32006  			if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;
 32007  			if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;
 32008  			if ( json.skinning !== undefined ) material.skinning = json.skinning;
 32009  			if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets;
 32010  
 32011  			// for PointsMaterial
 32012  
 32013  			if ( json.size !== undefined ) material.size = json.size;
 32014  			if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;
 32015  
 32016  			// maps
 32017  
 32018  			if ( json.map !== undefined ) material.map = getTexture( json.map );
 32019  
 32020  			if ( json.alphaMap !== undefined ) {
 32021  
 32022  				material.alphaMap = getTexture( json.alphaMap );
 32023  				material.transparent = true;
 32024  
 32025  			}
 32026  
 32027  			if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );
 32028  			if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;
 32029  
 32030  			if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );
 32031  			if ( json.normalScale !== undefined ) {
 32032  
 32033  				var normalScale = json.normalScale;
 32034  
 32035  				if ( Array.isArray( normalScale ) === false ) {
 32036  
 32037  					// Blender exporter used to export a scalar. See #7459
 32038  
 32039  					normalScale = [ normalScale, normalScale ];
 32040  
 32041  				}
 32042  
 32043  				material.normalScale = new Vector2().fromArray( normalScale );
 32044  
 32045  			}
 32046  
 32047  			if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );
 32048  			if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;
 32049  			if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;
 32050  
 32051  			if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );
 32052  			if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );
 32053  
 32054  			if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );
 32055  			if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;
 32056  
 32057  			if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );
 32058  
 32059  			if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );
 32060  
 32061  			if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;
 32062  
 32063  			if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );
 32064  			if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;
 32065  
 32066  			if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );
 32067  			if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;
 32068  
 32069  			if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );
 32070  
 32071  			// MultiMaterial
 32072  
 32073  			if ( json.materials !== undefined ) {
 32074  
 32075  				for ( var i = 0, l = json.materials.length; i < l; i ++ ) {
 32076  
 32077  					material.materials.push( this.parse( json.materials[ i ] ) );
 32078  
 32079  				}
 32080  
 32081  			}
 32082  
 32083  			return material;
 32084  
 32085  		}
 32086  
 32087  	} );
 32088  
 32089  	/**
 32090  	 * @author mrdoob / http://mrdoob.com/
 32091  	 */
 32092  
 32093  	function BufferGeometryLoader( manager ) {
 32094  
 32095  		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
 32096  
 32097  	}
 32098  
 32099  	Object.assign( BufferGeometryLoader.prototype, {
 32100  
 32101  		load: function ( url, onLoad, onProgress, onError ) {
 32102  
 32103  			var scope = this;
 32104  
 32105  			var loader = new FileLoader( scope.manager );
 32106  			loader.load( url, function ( text ) {
 32107  
 32108  				onLoad( scope.parse( JSON.parse( text ) ) );
 32109  
 32110  			}, onProgress, onError );
 32111  
 32112  		},
 32113  
 32114  		parse: function ( json ) {
 32115  
 32116  			var geometry = new BufferGeometry();
 32117  
 32118  			var index = json.data.index;
 32119  
 32120  			var TYPED_ARRAYS = {
 32121  				'Int8Array': Int8Array,
 32122  				'Uint8Array': Uint8Array,
 32123  				'Uint8ClampedArray': Uint8ClampedArray,
 32124  				'Int16Array': Int16Array,
 32125  				'Uint16Array': Uint16Array,
 32126  				'Int32Array': Int32Array,
 32127  				'Uint32Array': Uint32Array,
 32128  				'Float32Array': Float32Array,
 32129  				'Float64Array': Float64Array
 32130  			};
 32131  
 32132  			if ( index !== undefined ) {
 32133  
 32134  				var typedArray = new TYPED_ARRAYS[ index.type ]( index.array );
 32135  				geometry.setIndex( new BufferAttribute( typedArray, 1 ) );
 32136  
 32137  			}
 32138  
 32139  			var attributes = json.data.attributes;
 32140  
 32141  			for ( var key in attributes ) {
 32142  
 32143  				var attribute = attributes[ key ];
 32144  				var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array );
 32145  
 32146  				geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) );
 32147  
 32148  			}
 32149  
 32150  			var groups = json.data.groups || json.data.drawcalls || json.data.offsets;
 32151  
 32152  			if ( groups !== undefined ) {
 32153  
 32154  				for ( var i = 0, n = groups.length; i !== n; ++ i ) {
 32155  
 32156  					var group = groups[ i ];
 32157  
 32158  					geometry.addGroup( group.start, group.count, group.materialIndex );
 32159  
 32160  				}
 32161  
 32162  			}
 32163  
 32164  			var boundingSphere = json.data.boundingSphere;
 32165  
 32166  			if ( boundingSphere !== undefined ) {
 32167  
 32168  				var center = new Vector3();
 32169  
 32170  				if ( boundingSphere.center !== undefined ) {
 32171  
 32172  					center.fromArray( boundingSphere.center );
 32173  
 32174  				}
 32175  
 32176  				geometry.boundingSphere = new Sphere( center, boundingSphere.radius );
 32177  
 32178  			}
 32179  
 32180  			return geometry;
 32181  
 32182  		}
 32183  
 32184  	} );
 32185  
 32186  	/**
 32187  	 * @author alteredq / http://alteredqualia.com/
 32188  	 */
 32189  
 32190  	function Loader() {
 32191  
 32192  		this.onLoadStart = function () {};
 32193  		this.onLoadProgress = function () {};
 32194  		this.onLoadComplete = function () {};
 32195  
 32196  	}
 32197  
 32198  	Loader.prototype = {
 32199  
 32200  		constructor: Loader,
 32201  
 32202  		crossOrigin: undefined,
 32203  
 32204  		extractUrlBase: function ( url ) {
 32205  
 32206  			var parts = url.split( '/' );
 32207  
 32208  			if ( parts.length === 1 ) return './';
 32209  
 32210  			parts.pop();
 32211  
 32212  			return parts.join( '/' ) + '/';
 32213  
 32214  		},
 32215  
 32216  		initMaterials: function ( materials, texturePath, crossOrigin ) {
 32217  
 32218  			var array = [];
 32219  
 32220  			for ( var i = 0; i < materials.length; ++ i ) {
 32221  
 32222  				array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin );
 32223  
 32224  			}
 32225  
 32226  			return array;
 32227  
 32228  		},
 32229  
 32230  		createMaterial: ( function () {
 32231  
 32232  			var BlendingMode = {
 32233  				NoBlending: NoBlending,
 32234  				NormalBlending: NormalBlending,
 32235  				AdditiveBlending: AdditiveBlending,
 32236  				SubtractiveBlending: SubtractiveBlending,
 32237  				MultiplyBlending: MultiplyBlending,
 32238  				CustomBlending: CustomBlending
 32239  			};
 32240  
 32241  			var color, textureLoader, materialLoader;
 32242  
 32243  			return function createMaterial( m, texturePath, crossOrigin ) {
 32244  
 32245  				if ( color === undefined ) color = new Color();
 32246  				if ( textureLoader === undefined ) textureLoader = new TextureLoader();
 32247  				if ( materialLoader === undefined ) materialLoader = new MaterialLoader();
 32248  
 32249  				// convert from old material format
 32250  
 32251  				var textures = {};
 32252  
 32253  				function loadTexture( path, repeat, offset, wrap, anisotropy ) {
 32254  
 32255  					var fullPath = texturePath + path;
 32256  					var loader = Loader.Handlers.get( fullPath );
 32257  
 32258  					var texture;
 32259  
 32260  					if ( loader !== null ) {
 32261  
 32262  						texture = loader.load( fullPath );
 32263  
 32264  					} else {
 32265  
 32266  						textureLoader.setCrossOrigin( crossOrigin );
 32267  						texture = textureLoader.load( fullPath );
 32268  
 32269  					}
 32270  
 32271  					if ( repeat !== undefined ) {
 32272  
 32273  						texture.repeat.fromArray( repeat );
 32274  
 32275  						if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping;
 32276  						if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping;
 32277  
 32278  					}
 32279  
 32280  					if ( offset !== undefined ) {
 32281  
 32282  						texture.offset.fromArray( offset );
 32283  
 32284  					}
 32285  
 32286  					if ( wrap !== undefined ) {
 32287  
 32288  						if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping;
 32289  						if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping;
 32290  
 32291  						if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping;
 32292  						if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping;
 32293  
 32294  					}
 32295  
 32296  					if ( anisotropy !== undefined ) {
 32297  
 32298  						texture.anisotropy = anisotropy;
 32299  
 32300  					}
 32301  
 32302  					var uuid = _Math.generateUUID();
 32303  
 32304  					textures[ uuid ] = texture;
 32305  
 32306  					return uuid;
 32307  
 32308  				}
 32309  
 32310  				//
 32311  
 32312  				var json = {
 32313  					uuid: _Math.generateUUID(),
 32314  					type: 'MeshLambertMaterial'
 32315  				};
 32316  
 32317  				for ( var name in m ) {
 32318  
 32319  					var value = m[ name ];
 32320  
 32321  					switch ( name ) {
 32322  
 32323  						case 'DbgColor':
 32324  						case 'DbgIndex':
 32325  						case 'opticalDensity':
 32326  						case 'illumination':
 32327  							break;
 32328  						case 'DbgName':
 32329  							json.name = value;
 32330  							break;
 32331  						case 'blending':
 32332  							json.blending = BlendingMode[ value ];
 32333  							break;
 32334  						case 'colorAmbient':
 32335  						case 'mapAmbient':
 32336  							console.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' );
 32337  							break;
 32338  						case 'colorDiffuse':
 32339  							json.color = color.fromArray( value ).getHex();
 32340  							break;
 32341  						case 'colorSpecular':
 32342  							json.specular = color.fromArray( value ).getHex();
 32343  							break;
 32344  						case 'colorEmissive':
 32345  							json.emissive = color.fromArray( value ).getHex();
 32346  							break;
 32347  						case 'specularCoef':
 32348  							json.shininess = value;
 32349  							break;
 32350  						case 'shading':
 32351  							if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial';
 32352  							if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial';
 32353  							if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial';
 32354  							break;
 32355  						case 'mapDiffuse':
 32356  							json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy );
 32357  							break;
 32358  						case 'mapDiffuseRepeat':
 32359  						case 'mapDiffuseOffset':
 32360  						case 'mapDiffuseWrap':
 32361  						case 'mapDiffuseAnisotropy':
 32362  							break;
 32363  						case 'mapEmissive':
 32364  							json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy );
 32365  							break;
 32366  						case 'mapEmissiveRepeat':
 32367  						case 'mapEmissiveOffset':
 32368  						case 'mapEmissiveWrap':
 32369  						case 'mapEmissiveAnisotropy':
 32370  							break;
 32371  						case 'mapLight':
 32372  							json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy );
 32373  							break;
 32374  						case 'mapLightRepeat':
 32375  						case 'mapLightOffset':
 32376  						case 'mapLightWrap':
 32377  						case 'mapLightAnisotropy':
 32378  							break;
 32379  						case 'mapAO':
 32380  							json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy );
 32381  							break;
 32382  						case 'mapAORepeat':
 32383  						case 'mapAOOffset':
 32384  						case 'mapAOWrap':
 32385  						case 'mapAOAnisotropy':
 32386  							break;
 32387  						case 'mapBump':
 32388  							json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy );
 32389  							break;
 32390  						case 'mapBumpScale':
 32391  							json.bumpScale = value;
 32392  							break;
 32393  						case 'mapBumpRepeat':
 32394  						case 'mapBumpOffset':
 32395  						case 'mapBumpWrap':
 32396  						case 'mapBumpAnisotropy':
 32397  							break;
 32398  						case 'mapNormal':
 32399  							json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy );
 32400  							break;
 32401  						case 'mapNormalFactor':
 32402  							json.normalScale = [ value, value ];
 32403  							break;
 32404  						case 'mapNormalRepeat':
 32405  						case 'mapNormalOffset':
 32406  						case 'mapNormalWrap':
 32407  						case 'mapNormalAnisotropy':
 32408  							break;
 32409  						case 'mapSpecular':
 32410  							json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy );
 32411  							break;
 32412  						case 'mapSpecularRepeat':
 32413  						case 'mapSpecularOffset':
 32414  						case 'mapSpecularWrap':
 32415  						case 'mapSpecularAnisotropy':
 32416  							break;
 32417  						case 'mapMetalness':
 32418  							json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy );
 32419  							break;
 32420  						case 'mapMetalnessRepeat':
 32421  						case 'mapMetalnessOffset':
 32422  						case 'mapMetalnessWrap':
 32423  						case 'mapMetalnessAnisotropy':
 32424  							break;
 32425  						case 'mapRoughness':
 32426  							json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy );
 32427  							break;
 32428  						case 'mapRoughnessRepeat':
 32429  						case 'mapRoughnessOffset':
 32430  						case 'mapRoughnessWrap':
 32431  						case 'mapRoughnessAnisotropy':
 32432  							break;
 32433  						case 'mapAlpha':
 32434  							json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy );
 32435  							break;
 32436  						case 'mapAlphaRepeat':
 32437  						case 'mapAlphaOffset':
 32438  						case 'mapAlphaWrap':
 32439  						case 'mapAlphaAnisotropy':
 32440  							break;
 32441  						case 'flipSided':
 32442  							json.side = BackSide;
 32443  							break;
 32444  						case 'doubleSided':
 32445  							json.side = DoubleSide;
 32446  							break;
 32447  						case 'transparency':
 32448  							console.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' );
 32449  							json.opacity = value;
 32450  							break;
 32451  						case 'depthTest':
 32452  						case 'depthWrite':
 32453  						case 'colorWrite':
 32454  						case 'opacity':
 32455  						case 'reflectivity':
 32456  						case 'transparent':
 32457  						case 'visible':
 32458  						case 'wireframe':
 32459  							json[ name ] = value;
 32460  							break;
 32461  						case 'vertexColors':
 32462  							if ( value === true ) json.vertexColors = VertexColors;
 32463  							if ( value === 'face' ) json.vertexColors = FaceColors;
 32464  							break;
 32465  						default:
 32466  							console.error( 'THREE.Loader.createMaterial: Unsupported', name, value );
 32467  							break;
 32468  
 32469  					}
 32470  
 32471  				}
 32472  
 32473  				if ( json.type === 'MeshBasicMaterial' ) delete json.emissive;
 32474  				if ( json.type !== 'MeshPhongMaterial' ) delete json.specular;
 32475  
 32476  				if ( json.opacity < 1 ) json.transparent = true;
 32477  
 32478  				materialLoader.setTextures( textures );
 32479  
 32480  				return materialLoader.parse( json );
 32481  
 32482  			};
 32483  
 32484  		} )()
 32485  
 32486  	};
 32487  
 32488  	Loader.Handlers = {
 32489  
 32490  		handlers: [],
 32491  
 32492  		add: function ( regex, loader ) {
 32493  
 32494  			this.handlers.push( regex, loader );
 32495  
 32496  		},
 32497  
 32498  		get: function ( file ) {
 32499  
 32500  			var handlers = this.handlers;
 32501  
 32502  			for ( var i = 0, l = handlers.length; i < l; i += 2 ) {
 32503  
 32504  				var regex = handlers[ i ];
 32505  				var loader = handlers[ i + 1 ];
 32506  
 32507  				if ( regex.test( file ) ) {
 32508  
 32509  					return loader;
 32510  
 32511  				}
 32512  
 32513  			}
 32514  
 32515  			return null;
 32516  
 32517  		}
 32518  
 32519  	};
 32520  
 32521  	/**
 32522  	 * @author mrdoob / http://mrdoob.com/
 32523  	 * @author alteredq / http://alteredqualia.com/
 32524  	 */
 32525  
 32526  	function JSONLoader( manager ) {
 32527  
 32528  		if ( typeof manager === 'boolean' ) {
 32529  
 32530  			console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' );
 32531  			manager = undefined;
 32532  
 32533  		}
 32534  
 32535  		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
 32536  
 32537  		this.withCredentials = false;
 32538  
 32539  	}
 32540  
 32541  	Object.assign( JSONLoader.prototype, {
 32542  
 32543  		load: function( url, onLoad, onProgress, onError ) {
 32544  
 32545  			var scope = this;
 32546  
 32547  			var texturePath = this.texturePath && ( typeof this.texturePath === "string" ) ? this.texturePath : Loader.prototype.extractUrlBase( url );
 32548  
 32549  			var loader = new FileLoader( this.manager );
 32550  			loader.setWithCredentials( this.withCredentials );
 32551  			loader.load( url, function ( text ) {
 32552  
 32553  				var json = JSON.parse( text );
 32554  				var metadata = json.metadata;
 32555  
 32556  				if ( metadata !== undefined ) {
 32557  
 32558  					var type = metadata.type;
 32559  
 32560  					if ( type !== undefined ) {
 32561  
 32562  						if ( type.toLowerCase() === 'object' ) {
 32563  
 32564  							console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' );
 32565  							return;
 32566  
 32567  						}
 32568  
 32569  						if ( type.toLowerCase() === 'scene' ) {
 32570  
 32571  							console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' );
 32572  							return;
 32573  
 32574  						}
 32575  
 32576  					}
 32577  
 32578  				}
 32579  
 32580  				var object = scope.parse( json, texturePath );
 32581  				onLoad( object.geometry, object.materials );
 32582  
 32583  			}, onProgress, onError );
 32584  
 32585  		},
 32586  
 32587  		setTexturePath: function ( value ) {
 32588  
 32589  			this.texturePath = value;
 32590  
 32591  		},
 32592  
 32593  		parse: function ( json, texturePath ) {
 32594  
 32595  			var geometry = new Geometry(),
 32596  			scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0;
 32597  
 32598  			parseModel( scale );
 32599  
 32600  			parseSkin();
 32601  			parseMorphing( scale );
 32602  			parseAnimations();
 32603  
 32604  			geometry.computeFaceNormals();
 32605  			geometry.computeBoundingSphere();
 32606  
 32607  			function parseModel( scale ) {
 32608  
 32609  				function isBitSet( value, position ) {
 32610  
 32611  					return value & ( 1 << position );
 32612  
 32613  				}
 32614  
 32615  				var i, j, fi,
 32616  
 32617  				offset, zLength,
 32618  
 32619  			colorIndex, normalIndex, uvIndex, materialIndex,
 32620  
 32621  				type,
 32622  				isQuad,
 32623  				hasMaterial,
 32624  				hasFaceVertexUv,
 32625  				hasFaceNormal, hasFaceVertexNormal,
 32626  				hasFaceColor, hasFaceVertexColor,
 32627  
 32628  			vertex, face, faceA, faceB, hex, normal,
 32629  
 32630  				uvLayer, uv, u, v,
 32631  
 32632  				faces = json.faces,
 32633  				vertices = json.vertices,
 32634  				normals = json.normals,
 32635  				colors = json.colors,
 32636  
 32637  				nUvLayers = 0;
 32638  
 32639  				if ( json.uvs !== undefined ) {
 32640  
 32641  					// disregard empty arrays
 32642  
 32643  					for ( i = 0; i < json.uvs.length; i ++ ) {
 32644  
 32645  						if ( json.uvs[ i ].length ) nUvLayers ++;
 32646  
 32647  					}
 32648  
 32649  					for ( i = 0; i < nUvLayers; i ++ ) {
 32650  
 32651  						geometry.faceVertexUvs[ i ] = [];
 32652  
 32653  					}
 32654  
 32655  				}
 32656  
 32657  				offset = 0;
 32658  				zLength = vertices.length;
 32659  
 32660  				while ( offset < zLength ) {
 32661  
 32662  					vertex = new Vector3();
 32663  
 32664  					vertex.x = vertices[ offset ++ ] * scale;
 32665  					vertex.y = vertices[ offset ++ ] * scale;
 32666  					vertex.z = vertices[ offset ++ ] * scale;
 32667  
 32668  					geometry.vertices.push( vertex );
 32669  
 32670  				}
 32671  
 32672  				offset = 0;
 32673  				zLength = faces.length;
 32674  
 32675  				while ( offset < zLength ) {
 32676  
 32677  					type = faces[ offset ++ ];
 32678  
 32679  
 32680  					isQuad              = isBitSet( type, 0 );
 32681  					hasMaterial         = isBitSet( type, 1 );
 32682  					hasFaceVertexUv     = isBitSet( type, 3 );
 32683  					hasFaceNormal       = isBitSet( type, 4 );
 32684  					hasFaceVertexNormal = isBitSet( type, 5 );
 32685  					hasFaceColor	     = isBitSet( type, 6 );
 32686  					hasFaceVertexColor  = isBitSet( type, 7 );
 32687  
 32688  					// console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);
 32689  
 32690  					if ( isQuad ) {
 32691  
 32692  						faceA = new Face3();
 32693  						faceA.a = faces[ offset ];
 32694  						faceA.b = faces[ offset + 1 ];
 32695  						faceA.c = faces[ offset + 3 ];
 32696  
 32697  						faceB = new Face3();
 32698  						faceB.a = faces[ offset + 1 ];
 32699  						faceB.b = faces[ offset + 2 ];
 32700  						faceB.c = faces[ offset + 3 ];
 32701  
 32702  						offset += 4;
 32703  
 32704  						if ( hasMaterial ) {
 32705  
 32706  							materialIndex = faces[ offset ++ ];
 32707  							faceA.materialIndex = materialIndex;
 32708  							faceB.materialIndex = materialIndex;
 32709  
 32710  						}
 32711  
 32712  						// to get face <=> uv index correspondence
 32713  
 32714  						fi = geometry.faces.length;
 32715  
 32716  						if ( hasFaceVertexUv ) {
 32717  
 32718  							for ( i = 0; i < nUvLayers; i ++ ) {
 32719  
 32720  								uvLayer = json.uvs[ i ];
 32721  
 32722  								geometry.faceVertexUvs[ i ][ fi ] = [];
 32723  								geometry.faceVertexUvs[ i ][ fi + 1 ] = [];
 32724  
 32725  								for ( j = 0; j < 4; j ++ ) {
 32726  
 32727  									uvIndex = faces[ offset ++ ];
 32728  
 32729  									u = uvLayer[ uvIndex * 2 ];
 32730  									v = uvLayer[ uvIndex * 2 + 1 ];
 32731  
 32732  									uv = new Vector2( u, v );
 32733  
 32734  									if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );
 32735  									if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );
 32736  
 32737  								}
 32738  
 32739  							}
 32740  
 32741  						}
 32742  
 32743  						if ( hasFaceNormal ) {
 32744  
 32745  							normalIndex = faces[ offset ++ ] * 3;
 32746  
 32747  							faceA.normal.set(
 32748  								normals[ normalIndex ++ ],
 32749  								normals[ normalIndex ++ ],
 32750  								normals[ normalIndex ]
 32751  							);
 32752  
 32753  							faceB.normal.copy( faceA.normal );
 32754  
 32755  						}
 32756  
 32757  						if ( hasFaceVertexNormal ) {
 32758  
 32759  							for ( i = 0; i < 4; i ++ ) {
 32760  
 32761  								normalIndex = faces[ offset ++ ] * 3;
 32762  
 32763  								normal = new Vector3(
 32764  									normals[ normalIndex ++ ],
 32765  									normals[ normalIndex ++ ],
 32766  									normals[ normalIndex ]
 32767  								);
 32768  
 32769  
 32770  								if ( i !== 2 ) faceA.vertexNormals.push( normal );
 32771  								if ( i !== 0 ) faceB.vertexNormals.push( normal );
 32772  
 32773  							}
 32774  
 32775  						}
 32776  
 32777  
 32778  						if ( hasFaceColor ) {
 32779  
 32780  							colorIndex = faces[ offset ++ ];
 32781  							hex = colors[ colorIndex ];
 32782  
 32783  							faceA.color.setHex( hex );
 32784  							faceB.color.setHex( hex );
 32785  
 32786  						}
 32787  
 32788  
 32789  						if ( hasFaceVertexColor ) {
 32790  
 32791  							for ( i = 0; i < 4; i ++ ) {
 32792  
 32793  								colorIndex = faces[ offset ++ ];
 32794  								hex = colors[ colorIndex ];
 32795  
 32796  								if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) );
 32797  								if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) );
 32798  
 32799  							}
 32800  
 32801  						}
 32802  
 32803  						geometry.faces.push( faceA );
 32804  						geometry.faces.push( faceB );
 32805  
 32806  					} else {
 32807  
 32808  						face = new Face3();
 32809  						face.a = faces[ offset ++ ];
 32810  						face.b = faces[ offset ++ ];
 32811  						face.c = faces[ offset ++ ];
 32812  
 32813  						if ( hasMaterial ) {
 32814  
 32815  							materialIndex = faces[ offset ++ ];
 32816  							face.materialIndex = materialIndex;
 32817  
 32818  						}
 32819  
 32820  						// to get face <=> uv index correspondence
 32821  
 32822  						fi = geometry.faces.length;
 32823  
 32824  						if ( hasFaceVertexUv ) {
 32825  
 32826  							for ( i = 0; i < nUvLayers; i ++ ) {
 32827  
 32828  								uvLayer = json.uvs[ i ];
 32829  
 32830  								geometry.faceVertexUvs[ i ][ fi ] = [];
 32831  
 32832  								for ( j = 0; j < 3; j ++ ) {
 32833  
 32834  									uvIndex = faces[ offset ++ ];
 32835  
 32836  									u = uvLayer[ uvIndex * 2 ];
 32837  									v = uvLayer[ uvIndex * 2 + 1 ];
 32838  
 32839  									uv = new Vector2( u, v );
 32840  
 32841  									geometry.faceVertexUvs[ i ][ fi ].push( uv );
 32842  
 32843  								}
 32844  
 32845  							}
 32846  
 32847  						}
 32848  
 32849  						if ( hasFaceNormal ) {
 32850  
 32851  							normalIndex = faces[ offset ++ ] * 3;
 32852  
 32853  							face.normal.set(
 32854  								normals[ normalIndex ++ ],
 32855  								normals[ normalIndex ++ ],
 32856  								normals[ normalIndex ]
 32857  							);
 32858  
 32859  						}
 32860  
 32861  						if ( hasFaceVertexNormal ) {
 32862  
 32863  							for ( i = 0; i < 3; i ++ ) {
 32864  
 32865  								normalIndex = faces[ offset ++ ] * 3;
 32866  
 32867  								normal = new Vector3(
 32868  									normals[ normalIndex ++ ],
 32869  									normals[ normalIndex ++ ],
 32870  									normals[ normalIndex ]
 32871  								);
 32872  
 32873  								face.vertexNormals.push( normal );
 32874  
 32875  							}
 32876  
 32877  						}
 32878  
 32879  
 32880  						if ( hasFaceColor ) {
 32881  
 32882  							colorIndex = faces[ offset ++ ];
 32883  							face.color.setHex( colors[ colorIndex ] );
 32884  
 32885  						}
 32886  
 32887  
 32888  						if ( hasFaceVertexColor ) {
 32889  
 32890  							for ( i = 0; i < 3; i ++ ) {
 32891  
 32892  								colorIndex = faces[ offset ++ ];
 32893  								face.vertexColors.push( new Color( colors[ colorIndex ] ) );
 32894  
 32895  							}
 32896  
 32897  						}
 32898  
 32899  						geometry.faces.push( face );
 32900  
 32901  					}
 32902  
 32903  				}
 32904  
 32905  			}
 32906  
 32907  			function parseSkin() {
 32908  
 32909  				var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2;
 32910  
 32911  				if ( json.skinWeights ) {
 32912  
 32913  					for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) {
 32914  
 32915  						var x =                               json.skinWeights[ i ];
 32916  						var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0;
 32917  						var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0;
 32918  						var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0;
 32919  
 32920  						geometry.skinWeights.push( new Vector4( x, y, z, w ) );
 32921  
 32922  					}
 32923  
 32924  				}
 32925  
 32926  				if ( json.skinIndices ) {
 32927  
 32928  					for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) {
 32929  
 32930  						var a =                               json.skinIndices[ i ];
 32931  						var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0;
 32932  						var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0;
 32933  						var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0;
 32934  
 32935  						geometry.skinIndices.push( new Vector4( a, b, c, d ) );
 32936  
 32937  					}
 32938  
 32939  				}
 32940  
 32941  				geometry.bones = json.bones;
 32942  
 32943  				if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) {
 32944  
 32945  					console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' +
 32946  						geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' );
 32947  
 32948  				}
 32949  
 32950  			}
 32951  
 32952  			function parseMorphing( scale ) {
 32953  
 32954  				if ( json.morphTargets !== undefined ) {
 32955  
 32956  					for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) {
 32957  
 32958  						geometry.morphTargets[ i ] = {};
 32959  						geometry.morphTargets[ i ].name = json.morphTargets[ i ].name;
 32960  						geometry.morphTargets[ i ].vertices = [];
 32961  
 32962  						var dstVertices = geometry.morphTargets[ i ].vertices;
 32963  						var srcVertices = json.morphTargets[ i ].vertices;
 32964  
 32965  						for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) {
 32966  
 32967  							var vertex = new Vector3();
 32968  							vertex.x = srcVertices[ v ] * scale;
 32969  							vertex.y = srcVertices[ v + 1 ] * scale;
 32970  							vertex.z = srcVertices[ v + 2 ] * scale;
 32971  
 32972  							dstVertices.push( vertex );
 32973  
 32974  						}
 32975  
 32976  					}
 32977  
 32978  				}
 32979  
 32980  				if ( json.morphColors !== undefined && json.morphColors.length > 0 ) {
 32981  
 32982  					console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' );
 32983  
 32984  					var faces = geometry.faces;
 32985  					var morphColors = json.morphColors[ 0 ].colors;
 32986  
 32987  					for ( var i = 0, l = faces.length; i < l; i ++ ) {
 32988  
 32989  						faces[ i ].color.fromArray( morphColors, i * 3 );
 32990  
 32991  					}
 32992  
 32993  				}
 32994  
 32995  			}
 32996  
 32997  			function parseAnimations() {
 32998  
 32999  				var outputAnimations = [];
 33000  
 33001  				// parse old style Bone/Hierarchy animations
 33002  				var animations = [];
 33003  
 33004  				if ( json.animation !== undefined ) {
 33005  
 33006  					animations.push( json.animation );
 33007  
 33008  				}
 33009  
 33010  				if ( json.animations !== undefined ) {
 33011  
 33012  					if ( json.animations.length ) {
 33013  
 33014  						animations = animations.concat( json.animations );
 33015  
 33016  					} else {
 33017  
 33018  						animations.push( json.animations );
 33019  
 33020  					}
 33021  
 33022  				}
 33023  
 33024  				for ( var i = 0; i < animations.length; i ++ ) {
 33025  
 33026  					var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones );
 33027  					if ( clip ) outputAnimations.push( clip );
 33028  
 33029  				}
 33030  
 33031  				// parse implicit morph animations
 33032  				if ( geometry.morphTargets ) {
 33033  
 33034  					// TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary.
 33035  					var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 );
 33036  					outputAnimations = outputAnimations.concat( morphAnimationClips );
 33037  
 33038  				}
 33039  
 33040  				if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations;
 33041  
 33042  			}
 33043  
 33044  			if ( json.materials === undefined || json.materials.length === 0 ) {
 33045  
 33046  				return { geometry: geometry };
 33047  
 33048  			} else {
 33049  
 33050  				var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin );
 33051  
 33052  				return { geometry: geometry, materials: materials };
 33053  
 33054  			}
 33055  
 33056  		}
 33057  
 33058  	} );
 33059  
 33060  	/**
 33061  	 * @author mrdoob / http://mrdoob.com/
 33062  	 */
 33063  
 33064  	function ObjectLoader( manager ) {
 33065  
 33066  		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
 33067  		this.texturePath = '';
 33068  
 33069  	}
 33070  
 33071  	Object.assign( ObjectLoader.prototype, {
 33072  
 33073  		load: function ( url, onLoad, onProgress, onError ) {
 33074  
 33075  			if ( this.texturePath === '' ) {
 33076  
 33077  				this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 );
 33078  
 33079  			}
 33080  
 33081  			var scope = this;
 33082  
 33083  			var loader = new FileLoader( scope.manager );
 33084  			loader.load( url, function ( text ) {
 33085  
 33086  				var json = null;
 33087  
 33088  				try {
 33089  
 33090  					json = JSON.parse( text );
 33091  
 33092  				} catch ( error ) {
 33093  
 33094  					if ( onError !== undefined ) onError( error );
 33095  
 33096  					console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message );
 33097  
 33098  					return;
 33099  
 33100  				}
 33101  
 33102  				var metadata = json.metadata;
 33103  
 33104  				if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {
 33105  
 33106  					console.error( 'THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.' );
 33107  					return;
 33108  
 33109  				}
 33110  
 33111  				scope.parse( json, onLoad );
 33112  
 33113  			}, onProgress, onError );
 33114  
 33115  		},
 33116  
 33117  		setTexturePath: function ( value ) {
 33118  
 33119  			this.texturePath = value;
 33120  
 33121  		},
 33122  
 33123  		setCrossOrigin: function ( value ) {
 33124  
 33125  			this.crossOrigin = value;
 33126  
 33127  		},
 33128  
 33129  		parse: function ( json, onLoad ) {
 33130  
 33131  			var geometries = this.parseGeometries( json.geometries );
 33132  
 33133  			var images = this.parseImages( json.images, function () {
 33134  
 33135  				if ( onLoad !== undefined ) onLoad( object );
 33136  
 33137  			} );
 33138  
 33139  			var textures = this.parseTextures( json.textures, images );
 33140  			var materials = this.parseMaterials( json.materials, textures );
 33141  
 33142  			var object = this.parseObject( json.object, geometries, materials );
 33143  
 33144  			if ( json.animations ) {
 33145  
 33146  				object.animations = this.parseAnimations( json.animations );
 33147  
 33148  			}
 33149  
 33150  			if ( json.images === undefined || json.images.length === 0 ) {
 33151  
 33152  				if ( onLoad !== undefined ) onLoad( object );
 33153  
 33154  			}
 33155  
 33156  			return object;
 33157  
 33158  		},
 33159  
 33160  		parseGeometries: function ( json ) {
 33161  
 33162  			var geometries = {};
 33163  
 33164  			if ( json !== undefined ) {
 33165  
 33166  				var geometryLoader = new JSONLoader();
 33167  				var bufferGeometryLoader = new BufferGeometryLoader();
 33168  
 33169  				for ( var i = 0, l = json.length; i < l; i ++ ) {
 33170  
 33171  					var geometry;
 33172  					var data = json[ i ];
 33173  
 33174  					switch ( data.type ) {
 33175  
 33176  						case 'PlaneGeometry':
 33177  						case 'PlaneBufferGeometry':
 33178  
 33179  							geometry = new Geometries[ data.type ](
 33180  								data.width,
 33181  								data.height,
 33182  								data.widthSegments,
 33183  								data.heightSegments
 33184  							);
 33185  
 33186  							break;
 33187  
 33188  						case 'BoxGeometry':
 33189  						case 'BoxBufferGeometry':
 33190  						case 'CubeGeometry': // backwards compatible
 33191  
 33192  							geometry = new Geometries[ data.type ](
 33193  								data.width,
 33194  								data.height,
 33195  								data.depth,
 33196  								data.widthSegments,
 33197  								data.heightSegments,
 33198  								data.depthSegments
 33199  							);
 33200  
 33201  							break;
 33202  
 33203  						case 'CircleGeometry':
 33204  						case 'CircleBufferGeometry':
 33205  
 33206  							geometry = new Geometries[ data.type ](
 33207  								data.radius,
 33208  								data.segments,
 33209  								data.thetaStart,
 33210  								data.thetaLength
 33211  							);
 33212  
 33213  							break;
 33214  
 33215  						case 'CylinderGeometry':
 33216  						case 'CylinderBufferGeometry':
 33217  
 33218  							geometry = new Geometries[ data.type ](
 33219  								data.radiusTop,
 33220  								data.radiusBottom,
 33221  								data.height,
 33222  								data.radialSegments,
 33223  								data.heightSegments,
 33224  								data.openEnded,
 33225  								data.thetaStart,
 33226  								data.thetaLength
 33227  							);
 33228  
 33229  							break;
 33230  
 33231  						case 'ConeGeometry':
 33232  						case 'ConeBufferGeometry':
 33233  
 33234  							geometry = new Geometries[ data.type ](
 33235  								data.radius,
 33236  								data.height,
 33237  								data.radialSegments,
 33238  								data.heightSegments,
 33239  								data.openEnded,
 33240  								data.thetaStart,
 33241  								data.thetaLength
 33242  							);
 33243  
 33244  							break;
 33245  
 33246  						case 'SphereGeometry':
 33247  						case 'SphereBufferGeometry':
 33248  
 33249  							geometry = new Geometries[ data.type ](
 33250  								data.radius,
 33251  								data.widthSegments,
 33252  								data.heightSegments,
 33253  								data.phiStart,
 33254  								data.phiLength,
 33255  								data.thetaStart,
 33256  								data.thetaLength
 33257  							);
 33258  
 33259  							break;
 33260  
 33261  						case 'DodecahedronGeometry':
 33262  						case 'IcosahedronGeometry':
 33263  						case 'OctahedronGeometry':
 33264  						case 'TetrahedronGeometry':
 33265  
 33266  							geometry = new Geometries[ data.type ](
 33267  								data.radius,
 33268  								data.detail
 33269  							);
 33270  
 33271  							break;
 33272  
 33273  						case 'RingGeometry':
 33274  						case 'RingBufferGeometry':
 33275  
 33276  							geometry = new Geometries[ data.type ](
 33277  								data.innerRadius,
 33278  								data.outerRadius,
 33279  								data.thetaSegments,
 33280  								data.phiSegments,
 33281  								data.thetaStart,
 33282  								data.thetaLength
 33283  							);
 33284  
 33285  							break;
 33286  
 33287  						case 'TorusGeometry':
 33288  						case 'TorusBufferGeometry':
 33289  
 33290  							geometry = new Geometries[ data.type ](
 33291  								data.radius,
 33292  								data.tube,
 33293  								data.radialSegments,
 33294  								data.tubularSegments,
 33295  								data.arc
 33296  							);
 33297  
 33298  							break;
 33299  
 33300  						case 'TorusKnotGeometry':
 33301  						case 'TorusKnotBufferGeometry':
 33302  
 33303  							geometry = new Geometries[ data.type ](
 33304  								data.radius,
 33305  								data.tube,
 33306  								data.tubularSegments,
 33307  								data.radialSegments,
 33308  								data.p,
 33309  								data.q
 33310  							);
 33311  
 33312  							break;
 33313  
 33314  						case 'LatheGeometry':
 33315  						case 'LatheBufferGeometry':
 33316  
 33317  							geometry = new Geometries[ data.type ](
 33318  								data.points,
 33319  								data.segments,
 33320  								data.phiStart,
 33321  								data.phiLength
 33322  							);
 33323  
 33324  							break;
 33325  
 33326  						case 'BufferGeometry':
 33327  
 33328  							geometry = bufferGeometryLoader.parse( data );
 33329  
 33330  							break;
 33331  
 33332  						case 'Geometry':
 33333  
 33334  							geometry = geometryLoader.parse( data.data, this.texturePath ).geometry;
 33335  
 33336  							break;
 33337  
 33338  						default:
 33339  
 33340  							console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' );
 33341  
 33342  							continue;
 33343  
 33344  					}
 33345  
 33346  					geometry.uuid = data.uuid;
 33347  
 33348  					if ( data.name !== undefined ) geometry.name = data.name;
 33349  
 33350  					geometries[ data.uuid ] = geometry;
 33351  
 33352  				}
 33353  
 33354  			}
 33355  
 33356  			return geometries;
 33357  
 33358  		},
 33359  
 33360  		parseMaterials: function ( json, textures ) {
 33361  
 33362  			var materials = {};
 33363  
 33364  			if ( json !== undefined ) {
 33365  
 33366  				var loader = new MaterialLoader();
 33367  				loader.setTextures( textures );
 33368  
 33369  				for ( var i = 0, l = json.length; i < l; i ++ ) {
 33370  
 33371  					var material = loader.parse( json[ i ] );
 33372  					materials[ material.uuid ] = material;
 33373  
 33374  				}
 33375  
 33376  			}
 33377  
 33378  			return materials;
 33379  
 33380  		},
 33381  
 33382  		parseAnimations: function ( json ) {
 33383  
 33384  			var animations = [];
 33385  
 33386  			for ( var i = 0; i < json.length; i ++ ) {
 33387  
 33388  				var clip = AnimationClip.parse( json[ i ] );
 33389  
 33390  				animations.push( clip );
 33391  
 33392  			}
 33393  
 33394  			return animations;
 33395  
 33396  		},
 33397  
 33398  		parseImages: function ( json, onLoad ) {
 33399  
 33400  			var scope = this;
 33401  			var images = {};
 33402  
 33403  			function loadImage( url ) {
 33404  
 33405  				scope.manager.itemStart( url );
 33406  
 33407  				return loader.load( url, function () {
 33408  
 33409  					scope.manager.itemEnd( url );
 33410  
 33411  				}, undefined, function () {
 33412  
 33413  					scope.manager.itemError( url );
 33414  
 33415  				} );
 33416  
 33417  			}
 33418  
 33419  			if ( json !== undefined && json.length > 0 ) {
 33420  
 33421  				var manager = new LoadingManager( onLoad );
 33422  
 33423  				var loader = new ImageLoader( manager );
 33424  				loader.setCrossOrigin( this.crossOrigin );
 33425  
 33426  				for ( var i = 0, l = json.length; i < l; i ++ ) {
 33427  
 33428  					var image = json[ i ];
 33429  					var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url;
 33430  
 33431  					images[ image.uuid ] = loadImage( path );
 33432  
 33433  				}
 33434  
 33435  			}
 33436  
 33437  			return images;
 33438  
 33439  		},
 33440  
 33441  		parseTextures: function ( json, images ) {
 33442  
 33443  			var TextureMapping = {
 33444  				UVMapping: UVMapping,
 33445  				CubeReflectionMapping: CubeReflectionMapping,
 33446  				CubeRefractionMapping: CubeRefractionMapping,
 33447  				EquirectangularReflectionMapping: EquirectangularReflectionMapping,
 33448  				EquirectangularRefractionMapping: EquirectangularRefractionMapping,
 33449  				SphericalReflectionMapping: SphericalReflectionMapping,
 33450  				CubeUVReflectionMapping: CubeUVReflectionMapping,
 33451  				CubeUVRefractionMapping: CubeUVRefractionMapping
 33452  			};
 33453  
 33454  			var TextureWrapping = {
 33455  				RepeatWrapping: RepeatWrapping,
 33456  				ClampToEdgeWrapping: ClampToEdgeWrapping,
 33457  				MirroredRepeatWrapping: MirroredRepeatWrapping
 33458  			};
 33459  
 33460  			var TextureFilter = {
 33461  				NearestFilter: NearestFilter,
 33462  				NearestMipMapNearestFilter: NearestMipMapNearestFilter,
 33463  				NearestMipMapLinearFilter: NearestMipMapLinearFilter,
 33464  				LinearFilter: LinearFilter,
 33465  				LinearMipMapNearestFilter: LinearMipMapNearestFilter,
 33466  				LinearMipMapLinearFilter: LinearMipMapLinearFilter
 33467  			};
 33468  
 33469  			function parseConstant( value, type ) {
 33470  
 33471  				if ( typeof( value ) === 'number' ) return value;
 33472  
 33473  				console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );
 33474  
 33475  				return type[ value ];
 33476  
 33477  			}
 33478  
 33479  			var textures = {};
 33480  
 33481  			if ( json !== undefined ) {
 33482  
 33483  				for ( var i = 0, l = json.length; i < l; i ++ ) {
 33484  
 33485  					var data = json[ i ];
 33486  
 33487  					if ( data.image === undefined ) {
 33488  
 33489  						console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid );
 33490  
 33491  					}
 33492  
 33493  					if ( images[ data.image ] === undefined ) {
 33494  
 33495  						console.warn( 'THREE.ObjectLoader: Undefined image', data.image );
 33496  
 33497  					}
 33498  
 33499  					var texture = new Texture( images[ data.image ] );
 33500  					texture.needsUpdate = true;
 33501  
 33502  					texture.uuid = data.uuid;
 33503  
 33504  					if ( data.name !== undefined ) texture.name = data.name;
 33505  
 33506  					if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TextureMapping );
 33507  
 33508  					if ( data.offset !== undefined ) texture.offset.fromArray( data.offset );
 33509  					if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );
 33510  					if ( data.wrap !== undefined ) {
 33511  
 33512  						texture.wrapS = parseConstant( data.wrap[ 0 ], TextureWrapping );
 33513  						texture.wrapT = parseConstant( data.wrap[ 1 ], TextureWrapping );
 33514  
 33515  					}
 33516  
 33517  					if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TextureFilter );
 33518  					if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TextureFilter );
 33519  					if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;
 33520  
 33521  					if ( data.flipY !== undefined ) texture.flipY = data.flipY;
 33522  
 33523  					textures[ data.uuid ] = texture;
 33524  
 33525  				}
 33526  
 33527  			}
 33528  
 33529  			return textures;
 33530  
 33531  		},
 33532  
 33533  		parseObject: function () {
 33534  
 33535  			var matrix = new Matrix4();
 33536  
 33537  			return function parseObject( data, geometries, materials ) {
 33538  
 33539  				var object;
 33540  
 33541  				function getGeometry( name ) {
 33542  
 33543  					if ( geometries[ name ] === undefined ) {
 33544  
 33545  						console.warn( 'THREE.ObjectLoader: Undefined geometry', name );
 33546  
 33547  					}
 33548  
 33549  					return geometries[ name ];
 33550  
 33551  				}
 33552  
 33553  				function getMaterial( name ) {
 33554  
 33555  					if ( name === undefined ) return undefined;
 33556  
 33557  					if ( materials[ name ] === undefined ) {
 33558  
 33559  						console.warn( 'THREE.ObjectLoader: Undefined material', name );
 33560  
 33561  					}
 33562  
 33563  					return materials[ name ];
 33564  
 33565  				}
 33566  
 33567  				switch ( data.type ) {
 33568  
 33569  					case 'Scene':
 33570  
 33571  						object = new Scene();
 33572  
 33573  						if ( data.background !== undefined ) {
 33574  
 33575  							if ( Number.isInteger( data.background ) ) {
 33576  
 33577  								object.background = new Color( data.background );
 33578  
 33579  							}
 33580  
 33581  						}
 33582  
 33583  						if ( data.fog !== undefined ) {
 33584  
 33585  							if ( data.fog.type === 'Fog' ) {
 33586  
 33587  								object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );
 33588  
 33589  							} else if ( data.fog.type === 'FogExp2' ) {
 33590  
 33591  								object.fog = new FogExp2( data.fog.color, data.fog.density );
 33592  
 33593  							}
 33594  
 33595  						}
 33596  
 33597  						break;
 33598  
 33599  					case 'PerspectiveCamera':
 33600  
 33601  						object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );
 33602  
 33603  						if ( data.focus !== undefined ) object.focus = data.focus;
 33604  						if ( data.zoom !== undefined ) object.zoom = data.zoom;
 33605  						if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;
 33606  						if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;
 33607  						if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
 33608  
 33609  						break;
 33610  
 33611  					case 'OrthographicCamera':
 33612  
 33613  						object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );
 33614  
 33615  						break;
 33616  
 33617  					case 'AmbientLight':
 33618  
 33619  						object = new AmbientLight( data.color, data.intensity );
 33620  
 33621  						break;
 33622  
 33623  					case 'DirectionalLight':
 33624  
 33625  						object = new DirectionalLight( data.color, data.intensity );
 33626  
 33627  						break;
 33628  
 33629  					case 'PointLight':
 33630  
 33631  						object = new PointLight( data.color, data.intensity, data.distance, data.decay );
 33632  
 33633  						break;
 33634  
 33635  					case 'SpotLight':
 33636  
 33637  						object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );
 33638  
 33639  						break;
 33640  
 33641  					case 'HemisphereLight':
 33642  
 33643  						object = new HemisphereLight( data.color, data.groundColor, data.intensity );
 33644  
 33645  						break;
 33646  
 33647  					case 'Mesh':
 33648  
 33649  						var geometry = getGeometry( data.geometry );
 33650  						var material = getMaterial( data.material );
 33651  
 33652  						if ( geometry.bones && geometry.bones.length > 0 ) {
 33653  
 33654  							object = new SkinnedMesh( geometry, material );
 33655  
 33656  						} else {
 33657  
 33658  							object = new Mesh( geometry, material );
 33659  
 33660  						}
 33661  
 33662  						break;
 33663  
 33664  					case 'LOD':
 33665  
 33666  						object = new LOD();
 33667  
 33668  						break;
 33669  
 33670  					case 'Line':
 33671  
 33672  						object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode );
 33673  
 33674  						break;
 33675  
 33676  					case 'LineSegments':
 33677  
 33678  						object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );
 33679  
 33680  						break;
 33681  
 33682  					case 'PointCloud':
 33683  					case 'Points':
 33684  
 33685  						object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );
 33686  
 33687  						break;
 33688  
 33689  					case 'Sprite':
 33690  
 33691  						object = new Sprite( getMaterial( data.material ) );
 33692  
 33693  						break;
 33694  
 33695  					case 'Group':
 33696  
 33697  						object = new Group();
 33698  
 33699  						break;
 33700  
 33701  					case 'SkinnedMesh':
 33702  
 33703  						console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh type. Instantiates Object3D instead.' );
 33704  
 33705  					default:
 33706  
 33707  						object = new Object3D();
 33708  
 33709  				}
 33710  
 33711  				object.uuid = data.uuid;
 33712  
 33713  				if ( data.name !== undefined ) object.name = data.name;
 33714  				if ( data.matrix !== undefined ) {
 33715  
 33716  					matrix.fromArray( data.matrix );
 33717  					matrix.decompose( object.position, object.quaternion, object.scale );
 33718  
 33719  				} else {
 33720  
 33721  					if ( data.position !== undefined ) object.position.fromArray( data.position );
 33722  					if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );
 33723  					if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );
 33724  					if ( data.scale !== undefined ) object.scale.fromArray( data.scale );
 33725  
 33726  				}
 33727  
 33728  				if ( data.castShadow !== undefined ) object.castShadow = data.castShadow;
 33729  				if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;
 33730  
 33731  				if ( data.shadow ) {
 33732  
 33733  					if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;
 33734  					if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;
 33735  					if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );
 33736  					if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );
 33737  
 33738  				}
 33739  
 33740  				if ( data.visible !== undefined ) object.visible = data.visible;
 33741  				if ( data.userData !== undefined ) object.userData = data.userData;
 33742  
 33743  				if ( data.children !== undefined ) {
 33744  
 33745  					for ( var child in data.children ) {
 33746  
 33747  						object.add( this.parseObject( data.children[ child ], geometries, materials ) );
 33748  
 33749  					}
 33750  
 33751  				}
 33752  
 33753  				if ( data.type === 'LOD' ) {
 33754  
 33755  					var levels = data.levels;
 33756  
 33757  					for ( var l = 0; l < levels.length; l ++ ) {
 33758  
 33759  						var level = levels[ l ];
 33760  						var child = object.getObjectByProperty( 'uuid', level.object );
 33761  
 33762  						if ( child !== undefined ) {
 33763  
 33764  							object.addLevel( child, level.distance );
 33765  
 33766  						}
 33767  
 33768  					}
 33769  
 33770  				}
 33771  
 33772  				return object;
 33773  
 33774  			};
 33775  
 33776  		}()
 33777  
 33778  	} );
 33779  
 33780  	/**
 33781  	 * @author zz85 / http://www.lab4games.net/zz85/blog
 33782  	 *
 33783  	 * Bezier Curves formulas obtained from
 33784  	 * http://en.wikipedia.org/wiki/Bézier_curve
 33785  	 */
 33786  
 33787  	function CatmullRom( t, p0, p1, p2, p3 ) {
 33788  
 33789  		var v0 = ( p2 - p0 ) * 0.5;
 33790  		var v1 = ( p3 - p1 ) * 0.5;
 33791  		var t2 = t * t;
 33792  		var t3 = t * t2;
 33793  		return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
 33794  
 33795  	}
 33796  
 33797  	//
 33798  
 33799  	function QuadraticBezierP0( t, p ) {
 33800  
 33801  		var k = 1 - t;
 33802  		return k * k * p;
 33803  
 33804  	}
 33805  
 33806  	function QuadraticBezierP1( t, p ) {
 33807  
 33808  		return 2 * ( 1 - t ) * t * p;
 33809  
 33810  	}
 33811  
 33812  	function QuadraticBezierP2( t, p ) {
 33813  
 33814  		return t * t * p;
 33815  
 33816  	}
 33817  
 33818  	function QuadraticBezier( t, p0, p1, p2 ) {
 33819  
 33820  		return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
 33821  			QuadraticBezierP2( t, p2 );
 33822  
 33823  	}
 33824  
 33825  	//
 33826  
 33827  	function CubicBezierP0( t, p ) {
 33828  
 33829  		var k = 1 - t;
 33830  		return k * k * k * p;
 33831  
 33832  	}
 33833  
 33834  	function CubicBezierP1( t, p ) {
 33835  
 33836  		var k = 1 - t;
 33837  		return 3 * k * k * t * p;
 33838  
 33839  	}
 33840  
 33841  	function CubicBezierP2( t, p ) {
 33842  
 33843  		return 3 * ( 1 - t ) * t * t * p;
 33844  
 33845  	}
 33846  
 33847  	function CubicBezierP3( t, p ) {
 33848  
 33849  		return t * t * t * p;
 33850  
 33851  	}
 33852  
 33853  	function CubicBezier( t, p0, p1, p2, p3 ) {
 33854  
 33855  		return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
 33856  			CubicBezierP3( t, p3 );
 33857  
 33858  	}
 33859  
 33860  	/**
 33861  	 * @author zz85 / http://www.lab4games.net/zz85/blog
 33862  	 * Extensible curve object
 33863  	 *
 33864  	 * Some common of Curve methods
 33865  	 * .getPoint(t), getTangent(t)
 33866  	 * .getPointAt(u), getTangentAt(u)
 33867  	 * .getPoints(), .getSpacedPoints()
 33868  	 * .getLength()
 33869  	 * .updateArcLengths()
 33870  	 *
 33871  	 * This following classes subclasses THREE.Curve:
 33872  	 *
 33873  	 * -- 2d classes --
 33874  	 * THREE.LineCurve
 33875  	 * THREE.QuadraticBezierCurve
 33876  	 * THREE.CubicBezierCurve
 33877  	 * THREE.SplineCurve
 33878  	 * THREE.ArcCurve
 33879  	 * THREE.EllipseCurve
 33880  	 *
 33881  	 * -- 3d classes --
 33882  	 * THREE.LineCurve3
 33883  	 * THREE.QuadraticBezierCurve3
 33884  	 * THREE.CubicBezierCurve3
 33885  	 * THREE.CatmullRomCurve3
 33886  	 *
 33887  	 * A series of curves can be represented as a THREE.CurvePath
 33888  	 *
 33889  	 **/
 33890  
 33891  	/**************************************************************
 33892  	 *	Abstract Curve base class
 33893  	 **************************************************************/
 33894  
 33895  	function Curve() {}
 33896  
 33897  	Curve.prototype = {
 33898  
 33899  		constructor: Curve,
 33900  
 33901  		// Virtual base class method to overwrite and implement in subclasses
 33902  		//	- t [0 .. 1]
 33903  
 33904  		getPoint: function ( t ) {
 33905  
 33906  			console.warn( "THREE.Curve: Warning, getPoint() not implemented!" );
 33907  			return null;
 33908  
 33909  		},
 33910  
 33911  		// Get point at relative position in curve according to arc length
 33912  		// - u [0 .. 1]
 33913  
 33914  		getPointAt: function ( u ) {
 33915  
 33916  			var t = this.getUtoTmapping( u );
 33917  			return this.getPoint( t );
 33918  
 33919  		},
 33920  
 33921  		// Get sequence of points using getPoint( t )
 33922  
 33923  		getPoints: function ( divisions ) {
 33924  
 33925  			if ( isNaN( divisions ) ) divisions = 5;
 33926  
 33927  			var points = [];
 33928  
 33929  			for ( var d = 0; d <= divisions; d ++ ) {
 33930  
 33931  				points.push( this.getPoint( d / divisions ) );
 33932  
 33933  			}
 33934  
 33935  			return points;
 33936  
 33937  		},
 33938  
 33939  		// Get sequence of points using getPointAt( u )
 33940  
 33941  		getSpacedPoints: function ( divisions ) {
 33942  
 33943  			if ( isNaN( divisions ) ) divisions = 5;
 33944  
 33945  			var points = [];
 33946  
 33947  			for ( var d = 0; d <= divisions; d ++ ) {
 33948  
 33949  				points.push( this.getPointAt( d / divisions ) );
 33950  
 33951  			}
 33952  
 33953  			return points;
 33954  
 33955  		},
 33956  
 33957  		// Get total curve arc length
 33958  
 33959  		getLength: function () {
 33960  
 33961  			var lengths = this.getLengths();
 33962  			return lengths[ lengths.length - 1 ];
 33963  
 33964  		},
 33965  
 33966  		// Get list of cumulative segment lengths
 33967  
 33968  		getLengths: function ( divisions ) {
 33969  
 33970  			if ( isNaN( divisions ) ) divisions = ( this.__arcLengthDivisions ) ? ( this.__arcLengthDivisions ) : 200;
 33971  
 33972  			if ( this.cacheArcLengths
 33973  				&& ( this.cacheArcLengths.length === divisions + 1 )
 33974  				&& ! this.needsUpdate ) {
 33975  
 33976  				//console.log( "cached", this.cacheArcLengths );
 33977  				return this.cacheArcLengths;
 33978  
 33979  			}
 33980  
 33981  			this.needsUpdate = false;
 33982  
 33983  			var cache = [];
 33984  			var current, last = this.getPoint( 0 );
 33985  			var p, sum = 0;
 33986  
 33987  			cache.push( 0 );
 33988  
 33989  			for ( p = 1; p <= divisions; p ++ ) {
 33990  
 33991  				current = this.getPoint ( p / divisions );
 33992  				sum += current.distanceTo( last );
 33993  				cache.push( sum );
 33994  				last = current;
 33995  
 33996  			}
 33997  
 33998  			this.cacheArcLengths = cache;
 33999  
 34000  			return cache; // { sums: cache, sum:sum }; Sum is in the last element.
 34001  
 34002  		},
 34003  
 34004  		updateArcLengths: function() {
 34005  
 34006  			this.needsUpdate = true;
 34007  			this.getLengths();
 34008  
 34009  		},
 34010  
 34011  		// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
 34012  
 34013  		getUtoTmapping: function ( u, distance ) {
 34014  
 34015  			var arcLengths = this.getLengths();
 34016  
 34017  			var i = 0, il = arcLengths.length;
 34018  
 34019  			var targetArcLength; // The targeted u distance value to get
 34020  
 34021  			if ( distance ) {
 34022  
 34023  				targetArcLength = distance;
 34024  
 34025  			} else {
 34026  
 34027  				targetArcLength = u * arcLengths[ il - 1 ];
 34028  
 34029  			}
 34030  
 34031  			//var time = Date.now();
 34032  
 34033  			// binary search for the index with largest value smaller than target u distance
 34034  
 34035  			var low = 0, high = il - 1, comparison;
 34036  
 34037  			while ( low <= high ) {
 34038  
 34039  				i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
 34040  
 34041  				comparison = arcLengths[ i ] - targetArcLength;
 34042  
 34043  				if ( comparison < 0 ) {
 34044  
 34045  					low = i + 1;
 34046  
 34047  				} else if ( comparison > 0 ) {
 34048  
 34049  					high = i - 1;
 34050  
 34051  				} else {
 34052  
 34053  					high = i;
 34054  					break;
 34055  
 34056  					// DONE
 34057  
 34058  				}
 34059  
 34060  			}
 34061  
 34062  			i = high;
 34063  
 34064  			//console.log('b' , i, low, high, Date.now()- time);
 34065  
 34066  			if ( arcLengths[ i ] === targetArcLength ) {
 34067  
 34068  				var t = i / ( il - 1 );
 34069  				return t;
 34070  
 34071  			}
 34072  
 34073  			// we could get finer grain at lengths, or use simple interpolation between two points
 34074  
 34075  			var lengthBefore = arcLengths[ i ];
 34076  			var lengthAfter = arcLengths[ i + 1 ];
 34077  
 34078  			var segmentLength = lengthAfter - lengthBefore;
 34079  
 34080  			// determine where we are between the 'before' and 'after' points
 34081  
 34082  			var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
 34083  
 34084  			// add that fractional amount to t
 34085  
 34086  			var t = ( i + segmentFraction ) / ( il - 1 );
 34087  
 34088  			return t;
 34089  
 34090  		},
 34091  
 34092  		// Returns a unit vector tangent at t
 34093  		// In case any sub curve does not implement its tangent derivation,
 34094  		// 2 points a small delta apart will be used to find its gradient
 34095  		// which seems to give a reasonable approximation
 34096  
 34097  		getTangent: function( t ) {
 34098  
 34099  			var delta = 0.0001;
 34100  			var t1 = t - delta;
 34101  			var t2 = t + delta;
 34102  
 34103  			// Capping in case of danger
 34104  
 34105  			if ( t1 < 0 ) t1 = 0;
 34106  			if ( t2 > 1 ) t2 = 1;
 34107  
 34108  			var pt1 = this.getPoint( t1 );
 34109  			var pt2 = this.getPoint( t2 );
 34110  
 34111  			var vec = pt2.clone().sub( pt1 );
 34112  			return vec.normalize();
 34113  
 34114  		},
 34115  
 34116  		getTangentAt: function ( u ) {
 34117  
 34118  			var t = this.getUtoTmapping( u );
 34119  			return this.getTangent( t );
 34120  
 34121  		},
 34122  
 34123  		computeFrenetFrames: function ( segments, closed ) {
 34124  
 34125  			// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
 34126  
 34127  			var normal = new Vector3();
 34128  
 34129  			var tangents = [];
 34130  			var normals = [];
 34131  			var binormals = [];
 34132  
 34133  			var vec = new Vector3();
 34134  			var mat = new Matrix4();
 34135  
 34136  			var i, u, theta;
 34137  
 34138  			// compute the tangent vectors for each segment on the curve
 34139  
 34140  			for ( i = 0; i <= segments; i ++ ) {
 34141  
 34142  				u = i / segments;
 34143  
 34144  				tangents[ i ] = this.getTangentAt( u );
 34145  				tangents[ i ].normalize();
 34146  
 34147  			}
 34148  
 34149  			// select an initial normal vector perpendicular to the first tangent vector,
 34150  			// and in the direction of the minimum tangent xyz component
 34151  
 34152  			normals[ 0 ] = new Vector3();
 34153  			binormals[ 0 ] = new Vector3();
 34154  			var min = Number.MAX_VALUE;
 34155  			var tx = Math.abs( tangents[ 0 ].x );
 34156  			var ty = Math.abs( tangents[ 0 ].y );
 34157  			var tz = Math.abs( tangents[ 0 ].z );
 34158  
 34159  			if ( tx <= min ) {
 34160  
 34161  				min = tx;
 34162  				normal.set( 1, 0, 0 );
 34163  
 34164  			}
 34165  
 34166  			if ( ty <= min ) {
 34167  
 34168  				min = ty;
 34169  				normal.set( 0, 1, 0 );
 34170  
 34171  			}
 34172  
 34173  			if ( tz <= min ) {
 34174  
 34175  				normal.set( 0, 0, 1 );
 34176  
 34177  			}
 34178  
 34179  			vec.crossVectors( tangents[ 0 ], normal ).normalize();
 34180  
 34181  			normals[ 0 ].crossVectors( tangents[ 0 ], vec );
 34182  			binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
 34183  
 34184  
 34185  			// compute the slowly-varying normal and binormal vectors for each segment on the curve
 34186  
 34187  			for ( i = 1; i <= segments; i ++ ) {
 34188  
 34189  				normals[ i ] = normals[ i - 1 ].clone();
 34190  
 34191  				binormals[ i ] = binormals[ i - 1 ].clone();
 34192  
 34193  				vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
 34194  
 34195  				if ( vec.length() > Number.EPSILON ) {
 34196  
 34197  					vec.normalize();
 34198  
 34199  					theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
 34200  
 34201  					normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
 34202  
 34203  				}
 34204  
 34205  				binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
 34206  
 34207  			}
 34208  
 34209  			// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
 34210  
 34211  			if ( closed === true ) {
 34212  
 34213  				theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
 34214  				theta /= segments;
 34215  
 34216  				if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
 34217  
 34218  					theta = - theta;
 34219  
 34220  				}
 34221  
 34222  				for ( i = 1; i <= segments; i ++ ) {
 34223  
 34224  					// twist a little...
 34225  					normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
 34226  					binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
 34227  
 34228  				}
 34229  
 34230  			}
 34231  
 34232  			return {
 34233  				tangents: tangents,
 34234  				normals: normals,
 34235  				binormals: binormals
 34236  			};
 34237  
 34238  		}
 34239  
 34240  	};
 34241  
 34242  	function LineCurve( v1, v2 ) {
 34243  
 34244  		this.v1 = v1;
 34245  		this.v2 = v2;
 34246  
 34247  	}
 34248  
 34249  	LineCurve.prototype = Object.create( Curve.prototype );
 34250  	LineCurve.prototype.constructor = LineCurve;
 34251  
 34252  	LineCurve.prototype.isLineCurve = true;
 34253  
 34254  	LineCurve.prototype.getPoint = function ( t ) {
 34255  
 34256  		if ( t === 1 ) {
 34257  
 34258  			return this.v2.clone();
 34259  
 34260  		}
 34261  
 34262  		var point = this.v2.clone().sub( this.v1 );
 34263  		point.multiplyScalar( t ).add( this.v1 );
 34264  
 34265  		return point;
 34266  
 34267  	};
 34268  
 34269  	// Line curve is linear, so we can overwrite default getPointAt
 34270  
 34271  	LineCurve.prototype.getPointAt = function ( u ) {
 34272  
 34273  		return this.getPoint( u );
 34274  
 34275  	};
 34276  
 34277  	LineCurve.prototype.getTangent = function ( t ) {
 34278  
 34279  		var tangent = this.v2.clone().sub( this.v1 );
 34280  
 34281  		return tangent.normalize();
 34282  
 34283  	};
 34284  
 34285  	/**
 34286  	 * @author zz85 / http://www.lab4games.net/zz85/blog
 34287  	 *
 34288  	 **/
 34289  
 34290  	/**************************************************************
 34291  	 *	Curved Path - a curve path is simply a array of connected
 34292  	 *  curves, but retains the api of a curve
 34293  	 **************************************************************/
 34294  
 34295  	function CurvePath() {
 34296  
 34297  		this.curves = [];
 34298  
 34299  		this.autoClose = false; // Automatically closes the path
 34300  
 34301  	}
 34302  
 34303  	CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), {
 34304  
 34305  		constructor: CurvePath,
 34306  
 34307  		add: function ( curve ) {
 34308  
 34309  			this.curves.push( curve );
 34310  
 34311  		},
 34312  
 34313  		closePath: function () {
 34314  
 34315  			// Add a line curve if start and end of lines are not connected
 34316  			var startPoint = this.curves[ 0 ].getPoint( 0 );
 34317  			var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
 34318  
 34319  			if ( ! startPoint.equals( endPoint ) ) {
 34320  
 34321  				this.curves.push( new LineCurve( endPoint, startPoint ) );
 34322  
 34323  			}
 34324  
 34325  		},
 34326  
 34327  		// To get accurate point with reference to
 34328  		// entire path distance at time t,
 34329  		// following has to be done:
 34330  
 34331  		// 1. Length of each sub path have to be known
 34332  		// 2. Locate and identify type of curve
 34333  		// 3. Get t for the curve
 34334  		// 4. Return curve.getPointAt(t')
 34335  
 34336  		getPoint: function ( t ) {
 34337  
 34338  			var d = t * this.getLength();
 34339  			var curveLengths = this.getCurveLengths();
 34340  			var i = 0;
 34341  
 34342  			// To think about boundaries points.
 34343  
 34344  			while ( i < curveLengths.length ) {
 34345  
 34346  				if ( curveLengths[ i ] >= d ) {
 34347  
 34348  					var diff = curveLengths[ i ] - d;
 34349  					var curve = this.curves[ i ];
 34350  
 34351  					var segmentLength = curve.getLength();
 34352  					var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
 34353  
 34354  					return curve.getPointAt( u );
 34355  
 34356  				}
 34357  
 34358  				i ++;
 34359  
 34360  			}
 34361  
 34362  			return null;
 34363  
 34364  			// loop where sum != 0, sum > d , sum+1 <d
 34365  
 34366  		},
 34367  
 34368  		// We cannot use the default THREE.Curve getPoint() with getLength() because in
 34369  		// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
 34370  		// getPoint() depends on getLength
 34371  
 34372  		getLength: function () {
 34373  
 34374  			var lens = this.getCurveLengths();
 34375  			return lens[ lens.length - 1 ];
 34376  
 34377  		},
 34378  
 34379  		// cacheLengths must be recalculated.
 34380  		updateArcLengths: function () {
 34381  
 34382  			this.needsUpdate = true;
 34383  			this.cacheLengths = null;
 34384  			this.getLengths();
 34385  
 34386  		},
 34387  
 34388  		// Compute lengths and cache them
 34389  		// We cannot overwrite getLengths() because UtoT mapping uses it.
 34390  
 34391  		getCurveLengths: function () {
 34392  
 34393  			// We use cache values if curves and cache array are same length
 34394  
 34395  			if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
 34396  
 34397  				return this.cacheLengths;
 34398  
 34399  			}
 34400  
 34401  			// Get length of sub-curve
 34402  			// Push sums into cached array
 34403  
 34404  			var lengths = [], sums = 0;
 34405  
 34406  			for ( var i = 0, l = this.curves.length; i < l; i ++ ) {
 34407  
 34408  				sums += this.curves[ i ].getLength();
 34409  				lengths.push( sums );
 34410  
 34411  			}
 34412  
 34413  			this.cacheLengths = lengths;
 34414  
 34415  			return lengths;
 34416  
 34417  		},
 34418  
 34419  		getSpacedPoints: function ( divisions ) {
 34420  
 34421  			if ( isNaN( divisions ) ) divisions = 40;
 34422  
 34423  			var points = [];
 34424  
 34425  			for ( var i = 0; i <= divisions; i ++ ) {
 34426  
 34427  				points.push( this.getPoint( i / divisions ) );
 34428  
 34429  			}
 34430  
 34431  			if ( this.autoClose ) {
 34432  
 34433  				points.push( points[ 0 ] );
 34434  
 34435  			}
 34436  
 34437  			return points;
 34438  
 34439  		},
 34440  
 34441  		getPoints: function ( divisions ) {
 34442  
 34443  			divisions = divisions || 12;
 34444  
 34445  			var points = [], last;
 34446  
 34447  			for ( var i = 0, curves = this.curves; i < curves.length; i ++ ) {
 34448  
 34449  				var curve = curves[ i ];
 34450  				var resolution = (curve && curve.isEllipseCurve) ? divisions * 2
 34451  					: (curve && curve.isLineCurve) ? 1
 34452  					: (curve && curve.isSplineCurve) ? divisions * curve.points.length
 34453  					: divisions;
 34454  
 34455  				var pts = curve.getPoints( resolution );
 34456  
 34457  				for ( var j = 0; j < pts.length; j++ ) {
 34458  
 34459  					var point = pts[ j ];
 34460  
 34461  					if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
 34462  
 34463  					points.push( point );
 34464  					last = point;
 34465  
 34466  				}
 34467  
 34468  			}
 34469  
 34470  			if ( this.autoClose && points.length > 1 && !points[ points.length - 1 ].equals( points[ 0 ] ) ) {
 34471  
 34472  				points.push( points[ 0 ] );
 34473  
 34474  			}
 34475  
 34476  			return points;
 34477  
 34478  		},
 34479  
 34480  		/**************************************************************
 34481  		 *	Create Geometries Helpers
 34482  		 **************************************************************/
 34483  
 34484  		/// Generate geometry from path points (for Line or Points objects)
 34485  
 34486  		createPointsGeometry: function ( divisions ) {
 34487  
 34488  			var pts = this.getPoints( divisions );
 34489  			return this.createGeometry( pts );
 34490  
 34491  		},
 34492  
 34493  		// Generate geometry from equidistant sampling along the path
 34494  
 34495  		createSpacedPointsGeometry: function ( divisions ) {
 34496  
 34497  			var pts = this.getSpacedPoints( divisions );
 34498  			return this.createGeometry( pts );
 34499  
 34500  		},
 34501  
 34502  		createGeometry: function ( points ) {
 34503  
 34504  			var geometry = new Geometry();
 34505  
 34506  			for ( var i = 0, l = points.length; i < l; i ++ ) {
 34507  
 34508  				var point = points[ i ];
 34509  				geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );
 34510  
 34511  			}
 34512  
 34513  			return geometry;
 34514  
 34515  		}
 34516  
 34517  	} );
 34518  
 34519  	function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
 34520  
 34521  		this.aX = aX;
 34522  		this.aY = aY;
 34523  
 34524  		this.xRadius = xRadius;
 34525  		this.yRadius = yRadius;
 34526  
 34527  		this.aStartAngle = aStartAngle;
 34528  		this.aEndAngle = aEndAngle;
 34529  
 34530  		this.aClockwise = aClockwise;
 34531  
 34532  		this.aRotation = aRotation || 0;
 34533  
 34534  	}
 34535  
 34536  	EllipseCurve.prototype = Object.create( Curve.prototype );
 34537  	EllipseCurve.prototype.constructor = EllipseCurve;
 34538  
 34539  	EllipseCurve.prototype.isEllipseCurve = true;
 34540  
 34541  	EllipseCurve.prototype.getPoint = function ( t ) {
 34542  
 34543  		var twoPi = Math.PI * 2;
 34544  		var deltaAngle = this.aEndAngle - this.aStartAngle;
 34545  		var samePoints = Math.abs( deltaAngle ) < Number.EPSILON;
 34546  
 34547  		// ensures that deltaAngle is 0 .. 2 PI
 34548  		while ( deltaAngle < 0 ) deltaAngle += twoPi;
 34549  		while ( deltaAngle > twoPi ) deltaAngle -= twoPi;
 34550  
 34551  		if ( deltaAngle < Number.EPSILON ) {
 34552  
 34553  			if ( samePoints ) {
 34554  
 34555  				deltaAngle = 0;
 34556  
 34557  			} else {
 34558  
 34559  				deltaAngle = twoPi;
 34560  
 34561  			}
 34562  
 34563  		}
 34564  
 34565  		if ( this.aClockwise === true && ! samePoints ) {
 34566  
 34567  			if ( deltaAngle === twoPi ) {
 34568  
 34569  				deltaAngle = - twoPi;
 34570  
 34571  			} else {
 34572  
 34573  				deltaAngle = deltaAngle - twoPi;
 34574  
 34575  			}
 34576  
 34577  		}
 34578  
 34579  		var angle = this.aStartAngle + t * deltaAngle;
 34580  		var x = this.aX + this.xRadius * Math.cos( angle );
 34581  		var y = this.aY + this.yRadius * Math.sin( angle );
 34582  
 34583  		if ( this.aRotation !== 0 ) {
 34584  
 34585  			var cos = Math.cos( this.aRotation );
 34586  			var sin = Math.sin( this.aRotation );
 34587  
 34588  			var tx = x - this.aX;
 34589  			var ty = y - this.aY;
 34590  
 34591  			// Rotate the point about the center of the ellipse.
 34592  			x = tx * cos - ty * sin + this.aX;
 34593  			y = tx * sin + ty * cos + this.aY;
 34594  
 34595  		}
 34596  
 34597  		return new Vector2( x, y );
 34598  
 34599  	};
 34600  
 34601  	function SplineCurve( points /* array of Vector2 */ ) {
 34602  
 34603  		this.points = ( points === undefined ) ? [] : points;
 34604  
 34605  	}
 34606  
 34607  	SplineCurve.prototype = Object.create( Curve.prototype );
 34608  	SplineCurve.prototype.constructor = SplineCurve;
 34609  
 34610  	SplineCurve.prototype.isSplineCurve = true;
 34611  
 34612  	SplineCurve.prototype.getPoint = function ( t ) {
 34613  
 34614  		var points = this.points;
 34615  		var point = ( points.length - 1 ) * t;
 34616  
 34617  		var intPoint = Math.floor( point );
 34618  		var weight = point - intPoint;
 34619  
 34620  		var point0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];
 34621  		var point1 = points[ intPoint ];
 34622  		var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
 34623  		var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
 34624  
 34625  		return new Vector2(
 34626  			CatmullRom( weight, point0.x, point1.x, point2.x, point3.x ),
 34627  			CatmullRom( weight, point0.y, point1.y, point2.y, point3.y )
 34628  		);
 34629  
 34630  	};
 34631  
 34632  	function CubicBezierCurve( v0, v1, v2, v3 ) {
 34633  
 34634  		this.v0 = v0;
 34635  		this.v1 = v1;
 34636  		this.v2 = v2;
 34637  		this.v3 = v3;
 34638  
 34639  	}
 34640  
 34641  	CubicBezierCurve.prototype = Object.create( Curve.prototype );
 34642  	CubicBezierCurve.prototype.constructor = CubicBezierCurve;
 34643  
 34644  	CubicBezierCurve.prototype.getPoint = function ( t ) {
 34645  
 34646  		var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
 34647  
 34648  		return new Vector2(
 34649  			CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
 34650  			CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
 34651  		);
 34652  
 34653  	};
 34654  
 34655  	function QuadraticBezierCurve( v0, v1, v2 ) {
 34656  
 34657  		this.v0 = v0;
 34658  		this.v1 = v1;
 34659  		this.v2 = v2;
 34660  
 34661  	}
 34662  
 34663  	QuadraticBezierCurve.prototype = Object.create( Curve.prototype );
 34664  	QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve;
 34665  
 34666  	QuadraticBezierCurve.prototype.getPoint = function ( t ) {
 34667  
 34668  		var v0 = this.v0, v1 = this.v1, v2 = this.v2;
 34669  
 34670  		return new Vector2(
 34671  			QuadraticBezier( t, v0.x, v1.x, v2.x ),
 34672  			QuadraticBezier( t, v0.y, v1.y, v2.y )
 34673  		);
 34674  
 34675  	};
 34676  
 34677  	var PathPrototype = Object.assign( Object.create( CurvePath.prototype ), {
 34678  
 34679  		fromPoints: function ( vectors ) {
 34680  
 34681  			this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y );
 34682  
 34683  			for ( var i = 1, l = vectors.length; i < l; i ++ ) {
 34684  
 34685  				this.lineTo( vectors[ i ].x, vectors[ i ].y );
 34686  
 34687  			}
 34688  
 34689  		},
 34690  
 34691  		moveTo: function ( x, y ) {
 34692  
 34693  			this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
 34694  
 34695  		},
 34696  
 34697  		lineTo: function ( x, y ) {
 34698  
 34699  			var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );
 34700  			this.curves.push( curve );
 34701  
 34702  			this.currentPoint.set( x, y );
 34703  
 34704  		},
 34705  
 34706  		quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
 34707  
 34708  			var curve = new QuadraticBezierCurve(
 34709  				this.currentPoint.clone(),
 34710  				new Vector2( aCPx, aCPy ),
 34711  				new Vector2( aX, aY )
 34712  			);
 34713  
 34714  			this.curves.push( curve );
 34715  
 34716  			this.currentPoint.set( aX, aY );
 34717  
 34718  		},
 34719  
 34720  		bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
 34721  
 34722  			var curve = new CubicBezierCurve(
 34723  				this.currentPoint.clone(),
 34724  				new Vector2( aCP1x, aCP1y ),
 34725  				new Vector2( aCP2x, aCP2y ),
 34726  				new Vector2( aX, aY )
 34727  			);
 34728  
 34729  			this.curves.push( curve );
 34730  
 34731  			this.currentPoint.set( aX, aY );
 34732  
 34733  		},
 34734  
 34735  		splineThru: function ( pts /*Array of Vector*/ ) {
 34736  
 34737  			var npts = [ this.currentPoint.clone() ].concat( pts );
 34738  
 34739  			var curve = new SplineCurve( npts );
 34740  			this.curves.push( curve );
 34741  
 34742  			this.currentPoint.copy( pts[ pts.length - 1 ] );
 34743  
 34744  		},
 34745  
 34746  		arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
 34747  
 34748  			var x0 = this.currentPoint.x;
 34749  			var y0 = this.currentPoint.y;
 34750  
 34751  			this.absarc( aX + x0, aY + y0, aRadius,
 34752  				aStartAngle, aEndAngle, aClockwise );
 34753  
 34754  		},
 34755  
 34756  		absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
 34757  
 34758  			this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
 34759  
 34760  		},
 34761  
 34762  		ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
 34763  
 34764  			var x0 = this.currentPoint.x;
 34765  			var y0 = this.currentPoint.y;
 34766  
 34767  			this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
 34768  
 34769  		},
 34770  
 34771  		absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {
 34772  
 34773  			var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );
 34774  
 34775  			if ( this.curves.length > 0 ) {
 34776  
 34777  				// if a previous curve is present, attempt to join
 34778  				var firstPoint = curve.getPoint( 0 );
 34779  
 34780  				if ( ! firstPoint.equals( this.currentPoint ) ) {
 34781  
 34782  					this.lineTo( firstPoint.x, firstPoint.y );
 34783  
 34784  				}
 34785  
 34786  			}
 34787  
 34788  			this.curves.push( curve );
 34789  
 34790  			var lastPoint = curve.getPoint( 1 );
 34791  			this.currentPoint.copy( lastPoint );
 34792  
 34793  		}
 34794  
 34795  	} );
 34796  
 34797  	/**
 34798  	 * @author zz85 / http://www.lab4games.net/zz85/blog
 34799  	 * Creates free form 2d path using series of points, lines or curves.
 34800  	 **/
 34801  
 34802  	function Path( points ) {
 34803  
 34804  		CurvePath.call( this );
 34805  		this.currentPoint = new Vector2();
 34806  
 34807  		if ( points ) {
 34808  
 34809  			this.fromPoints( points );
 34810  
 34811  		}
 34812  
 34813  	}
 34814  
 34815  	Path.prototype = PathPrototype;
 34816  	PathPrototype.constructor = Path;
 34817  
 34818  	/**
 34819  	 * @author zz85 / http://www.lab4games.net/zz85/blog
 34820  	 * Defines a 2d shape plane using paths.
 34821  	 **/
 34822  
 34823  	// STEP 1 Create a path.
 34824  	// STEP 2 Turn path into shape.
 34825  	// STEP 3 ExtrudeGeometry takes in Shape/Shapes
 34826  	// STEP 3a - Extract points from each shape, turn to vertices
 34827  	// STEP 3b - Triangulate each shape, add faces.
 34828  
 34829  	function Shape() {
 34830  
 34831  		Path.apply( this, arguments );
 34832  
 34833  		this.holes = [];
 34834  
 34835  	}
 34836  
 34837  	Shape.prototype = Object.assign( Object.create( PathPrototype ), {
 34838  
 34839  		constructor: Shape,
 34840  
 34841  		getPointsHoles: function ( divisions ) {
 34842  
 34843  			var holesPts = [];
 34844  
 34845  			for ( var i = 0, l = this.holes.length; i < l; i ++ ) {
 34846  
 34847  				holesPts[ i ] = this.holes[ i ].getPoints( divisions );
 34848  
 34849  			}
 34850  
 34851  			return holesPts;
 34852  
 34853  		},
 34854  
 34855  		// Get points of shape and holes (keypoints based on segments parameter)
 34856  
 34857  		extractAllPoints: function ( divisions ) {
 34858  
 34859  			return {
 34860  
 34861  				shape: this.getPoints( divisions ),
 34862  				holes: this.getPointsHoles( divisions )
 34863  
 34864  			};
 34865  
 34866  		},
 34867  
 34868  		extractPoints: function ( divisions ) {
 34869  
 34870  			return this.extractAllPoints( divisions );
 34871  
 34872  		}
 34873  
 34874  	} );
 34875  
 34876  	/**
 34877  	 * @author zz85 / http://www.lab4games.net/zz85/blog
 34878  	 * minimal class for proxing functions to Path. Replaces old "extractSubpaths()"
 34879  	 **/
 34880  
 34881  	function ShapePath() {
 34882  
 34883  		this.subPaths = [];
 34884  		this.currentPath = null;
 34885  
 34886  	}
 34887  
 34888  	ShapePath.prototype = {
 34889  
 34890  		moveTo: function ( x, y ) {
 34891  
 34892  			this.currentPath = new Path();
 34893  			this.subPaths.push( this.currentPath );
 34894  			this.currentPath.moveTo( x, y );
 34895  
 34896  		},
 34897  
 34898  		lineTo: function ( x, y ) {
 34899  
 34900  			this.currentPath.lineTo( x, y );
 34901  
 34902  		},
 34903  
 34904  		quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {
 34905  
 34906  			this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );
 34907  
 34908  		},
 34909  
 34910  		bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
 34911  
 34912  			this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );
 34913  
 34914  		},
 34915  
 34916  		splineThru: function ( pts ) {
 34917  
 34918  			this.currentPath.splineThru( pts );
 34919  
 34920  		},
 34921  
 34922  		toShapes: function ( isCCW, noHoles ) {
 34923  
 34924  			function toShapesNoHoles( inSubpaths ) {
 34925  
 34926  				var shapes = [];
 34927  
 34928  				for ( var i = 0, l = inSubpaths.length; i < l; i ++ ) {
 34929  
 34930  					var tmpPath = inSubpaths[ i ];
 34931  
 34932  					var tmpShape = new Shape();
 34933  					tmpShape.curves = tmpPath.curves;
 34934  
 34935  					shapes.push( tmpShape );
 34936  
 34937  				}
 34938  
 34939  				return shapes;
 34940  
 34941  			}
 34942  
 34943  			function isPointInsidePolygon( inPt, inPolygon ) {
 34944  
 34945  				var polyLen = inPolygon.length;
 34946  
 34947  				// inPt on polygon contour => immediate success    or
 34948  				// toggling of inside/outside at every single! intersection point of an edge
 34949  				//  with the horizontal line through inPt, left of inPt
 34950  				//  not counting lowerY endpoints of edges and whole edges on that line
 34951  				var inside = false;
 34952  				for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
 34953  
 34954  					var edgeLowPt  = inPolygon[ p ];
 34955  					var edgeHighPt = inPolygon[ q ];
 34956  
 34957  					var edgeDx = edgeHighPt.x - edgeLowPt.x;
 34958  					var edgeDy = edgeHighPt.y - edgeLowPt.y;
 34959  
 34960  					if ( Math.abs( edgeDy ) > Number.EPSILON ) {
 34961  
 34962  						// not parallel
 34963  						if ( edgeDy < 0 ) {
 34964  
 34965  							edgeLowPt  = inPolygon[ q ]; edgeDx = - edgeDx;
 34966  							edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
 34967  
 34968  						}
 34969  						if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) 		continue;
 34970  
 34971  						if ( inPt.y === edgeLowPt.y ) {
 34972  
 34973  							if ( inPt.x === edgeLowPt.x )		return	true;		// inPt is on contour ?
 34974  							// continue;				// no intersection or edgeLowPt => doesn't count !!!
 34975  
 34976  						} else {
 34977  
 34978  							var perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );
 34979  							if ( perpEdge === 0 )				return	true;		// inPt is on contour ?
 34980  							if ( perpEdge < 0 ) 				continue;
 34981  							inside = ! inside;		// true intersection left of inPt
 34982  
 34983  						}
 34984  
 34985  					} else {
 34986  
 34987  						// parallel or collinear
 34988  						if ( inPt.y !== edgeLowPt.y ) 		continue;			// parallel
 34989  						// edge lies on the same horizontal line as inPt
 34990  						if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
 34991  							 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) )		return	true;	// inPt: Point on contour !
 34992  						// continue;
 34993  
 34994  					}
 34995  
 34996  				}
 34997  
 34998  				return	inside;
 34999  
 35000  			}
 35001  
 35002  			var isClockWise = ShapeUtils.isClockWise;
 35003  
 35004  			var subPaths = this.subPaths;
 35005  			if ( subPaths.length === 0 ) return [];
 35006  
 35007  			if ( noHoles === true )	return	toShapesNoHoles( subPaths );
 35008  
 35009  
 35010  			var solid, tmpPath, tmpShape, shapes = [];
 35011  
 35012  			if ( subPaths.length === 1 ) {
 35013  
 35014  				tmpPath = subPaths[ 0 ];
 35015  				tmpShape = new Shape();
 35016  				tmpShape.curves = tmpPath.curves;
 35017  				shapes.push( tmpShape );
 35018  				return shapes;
 35019  
 35020  			}
 35021  
 35022  			var holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );
 35023  			holesFirst = isCCW ? ! holesFirst : holesFirst;
 35024  
 35025  			// console.log("Holes first", holesFirst);
 35026  
 35027  			var betterShapeHoles = [];
 35028  			var newShapes = [];
 35029  			var newShapeHoles = [];
 35030  			var mainIdx = 0;
 35031  			var tmpPoints;
 35032  
 35033  			newShapes[ mainIdx ] = undefined;
 35034  			newShapeHoles[ mainIdx ] = [];
 35035  
 35036  			for ( var i = 0, l = subPaths.length; i < l; i ++ ) {
 35037  
 35038  				tmpPath = subPaths[ i ];
 35039  				tmpPoints = tmpPath.getPoints();
 35040  				solid = isClockWise( tmpPoints );
 35041  				solid = isCCW ? ! solid : solid;
 35042  
 35043  				if ( solid ) {
 35044  
 35045  					if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) )	mainIdx ++;
 35046  
 35047  					newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };
 35048  					newShapes[ mainIdx ].s.curves = tmpPath.curves;
 35049  
 35050  					if ( holesFirst )	mainIdx ++;
 35051  					newShapeHoles[ mainIdx ] = [];
 35052  
 35053  					//console.log('cw', i);
 35054  
 35055  				} else {
 35056  
 35057  					newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );
 35058  
 35059  					//console.log('ccw', i);
 35060  
 35061  				}
 35062  
 35063  			}
 35064  
 35065  			// only Holes? -> probably all Shapes with wrong orientation
 35066  			if ( ! newShapes[ 0 ] )	return	toShapesNoHoles( subPaths );
 35067  
 35068  
 35069  			if ( newShapes.length > 1 ) {
 35070  
 35071  				var ambiguous = false;
 35072  				var toChange = [];
 35073  
 35074  				for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
 35075  
 35076  					betterShapeHoles[ sIdx ] = [];
 35077  
 35078  				}
 35079  
 35080  				for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
 35081  
 35082  					var sho = newShapeHoles[ sIdx ];
 35083  
 35084  					for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) {
 35085  
 35086  						var ho = sho[ hIdx ];
 35087  						var hole_unassigned = true;
 35088  
 35089  						for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
 35090  
 35091  							if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {
 35092  
 35093  								if ( sIdx !== s2Idx )	toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );
 35094  								if ( hole_unassigned ) {
 35095  
 35096  									hole_unassigned = false;
 35097  									betterShapeHoles[ s2Idx ].push( ho );
 35098  
 35099  								} else {
 35100  
 35101  									ambiguous = true;
 35102  
 35103  								}
 35104  
 35105  							}
 35106  
 35107  						}
 35108  						if ( hole_unassigned ) {
 35109  
 35110  							betterShapeHoles[ sIdx ].push( ho );
 35111  
 35112  						}
 35113  
 35114  					}
 35115  
 35116  				}
 35117  				// console.log("ambiguous: ", ambiguous);
 35118  				if ( toChange.length > 0 ) {
 35119  
 35120  					// console.log("to change: ", toChange);
 35121  					if ( ! ambiguous )	newShapeHoles = betterShapeHoles;
 35122  
 35123  				}
 35124  
 35125  			}
 35126  
 35127  			var tmpHoles;
 35128  
 35129  			for ( var i = 0, il = newShapes.length; i < il; i ++ ) {
 35130  
 35131  				tmpShape = newShapes[ i ].s;
 35132  				shapes.push( tmpShape );
 35133  				tmpHoles = newShapeHoles[ i ];
 35134  
 35135  				for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
 35136  
 35137  					tmpShape.holes.push( tmpHoles[ j ].h );
 35138  
 35139  				}
 35140  
 35141  			}
 35142  
 35143  			//console.log("shape", shapes);
 35144  
 35145  			return shapes;
 35146  
 35147  		}
 35148  
 35149  	};
 35150  
 35151  	/**
 35152  	 * @author zz85 / http://www.lab4games.net/zz85/blog
 35153  	 * @author mrdoob / http://mrdoob.com/
 35154  	 */
 35155  
 35156  	function Font( data ) {
 35157  
 35158  		this.data = data;
 35159  
 35160  	}
 35161  
 35162  	Object.assign( Font.prototype, {
 35163  
 35164  		isFont: true,
 35165  
 35166  		generateShapes: function ( text, size, divisions ) {
 35167  
 35168  			function createPaths( text ) {
 35169  
 35170  				var chars = String( text ).split( '' );
 35171  				var scale = size / data.resolution;
 35172  				var line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale;
 35173  
 35174  				var offsetX = 0, offsetY = 0;
 35175  
 35176  				var paths = [];
 35177  
 35178  				for ( var i = 0; i < chars.length; i ++ ) {
 35179  
 35180  					var char = chars[ i ];
 35181  
 35182  					if ( char === '\n' ) {
 35183  
 35184  						offsetX = 0;
 35185  						offsetY -= line_height;
 35186  
 35187  					} else {
 35188  
 35189  						var ret = createPath( char, scale, offsetX, offsetY );
 35190  						offsetX += ret.offsetX;
 35191  						paths.push( ret.path );
 35192  
 35193  					}
 35194  
 35195  				}
 35196  
 35197  				return paths;
 35198  
 35199  			}
 35200  
 35201  			function createPath( c, scale, offsetX, offsetY ) {
 35202  
 35203  				var glyph = data.glyphs[ c ] || data.glyphs[ '?' ];
 35204  
 35205  				if ( ! glyph ) return;
 35206  
 35207  				var path = new ShapePath();
 35208  
 35209  				var pts = [];
 35210  				var x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, laste;
 35211  
 35212  				if ( glyph.o ) {
 35213  
 35214  					var outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
 35215  
 35216  					for ( var i = 0, l = outline.length; i < l; ) {
 35217  
 35218  						var action = outline[ i ++ ];
 35219  
 35220  						switch ( action ) {
 35221  
 35222  							case 'm': // moveTo
 35223  
 35224  								x = outline[ i ++ ] * scale + offsetX;
 35225  								y = outline[ i ++ ] * scale + offsetY;
 35226  
 35227  								path.moveTo( x, y );
 35228  
 35229  								break;
 35230  
 35231  							case 'l': // lineTo
 35232  
 35233  								x = outline[ i ++ ] * scale + offsetX;
 35234  								y = outline[ i ++ ] * scale + offsetY;
 35235  
 35236  								path.lineTo( x, y );
 35237  
 35238  								break;
 35239  
 35240  							case 'q': // quadraticCurveTo
 35241  
 35242  								cpx  = outline[ i ++ ] * scale + offsetX;
 35243  								cpy  = outline[ i ++ ] * scale + offsetY;
 35244  								cpx1 = outline[ i ++ ] * scale + offsetX;
 35245  								cpy1 = outline[ i ++ ] * scale + offsetY;
 35246  
 35247  								path.quadraticCurveTo( cpx1, cpy1, cpx, cpy );
 35248  
 35249  								laste = pts[ pts.length - 1 ];
 35250  
 35251  								if ( laste ) {
 35252  
 35253  									cpx0 = laste.x;
 35254  									cpy0 = laste.y;
 35255  
 35256  									for ( var i2 = 1; i2 <= divisions; i2 ++ ) {
 35257  
 35258  										var t = i2 / divisions;
 35259  										QuadraticBezier( t, cpx0, cpx1, cpx );
 35260  										QuadraticBezier( t, cpy0, cpy1, cpy );
 35261  
 35262  									}
 35263  
 35264  								}
 35265  
 35266  								break;
 35267  
 35268  							case 'b': // bezierCurveTo
 35269  
 35270  								cpx  = outline[ i ++ ] * scale + offsetX;
 35271  								cpy  = outline[ i ++ ] * scale + offsetY;
 35272  								cpx1 = outline[ i ++ ] * scale + offsetX;
 35273  								cpy1 = outline[ i ++ ] * scale + offsetY;
 35274  								cpx2 = outline[ i ++ ] * scale + offsetX;
 35275  								cpy2 = outline[ i ++ ] * scale + offsetY;
 35276  
 35277  								path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );
 35278  
 35279  								laste = pts[ pts.length - 1 ];
 35280  
 35281  								if ( laste ) {
 35282  
 35283  									cpx0 = laste.x;
 35284  									cpy0 = laste.y;
 35285  
 35286  									for ( var i2 = 1; i2 <= divisions; i2 ++ ) {
 35287  
 35288  										var t = i2 / divisions;
 35289  										CubicBezier( t, cpx0, cpx1, cpx2, cpx );
 35290  										CubicBezier( t, cpy0, cpy1, cpy2, cpy );
 35291  
 35292  									}
 35293  
 35294  								}
 35295  
 35296  								break;
 35297  
 35298  						}
 35299  
 35300  					}
 35301  
 35302  				}
 35303  
 35304  				return { offsetX: glyph.ha * scale, path: path };
 35305  
 35306  			}
 35307  
 35308  			//
 35309  
 35310  			if ( size === undefined ) size = 100;
 35311  			if ( divisions === undefined ) divisions = 4;
 35312  
 35313  			var data = this.data;
 35314  
 35315  			var paths = createPaths( text );
 35316  			var shapes = [];
 35317  
 35318  			for ( var p = 0, pl = paths.length; p < pl; p ++ ) {
 35319  
 35320  				Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
 35321  
 35322  			}
 35323  
 35324  			return shapes;
 35325  
 35326  		}
 35327  
 35328  	} );
 35329  
 35330  	/**
 35331  	 * @author mrdoob / http://mrdoob.com/
 35332  	 */
 35333  
 35334  	function FontLoader( manager ) {
 35335  
 35336  		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
 35337  
 35338  	}
 35339  
 35340  	Object.assign( FontLoader.prototype, {
 35341  
 35342  		load: function ( url, onLoad, onProgress, onError ) {
 35343  
 35344  			var scope = this;
 35345  
 35346  			var loader = new FileLoader( this.manager );
 35347  			loader.load( url, function ( text ) {
 35348  
 35349  				var json;
 35350  
 35351  				try {
 35352  
 35353  					json = JSON.parse( text );
 35354  
 35355  				} catch ( e ) {
 35356  
 35357  					console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' );
 35358  					json = JSON.parse( text.substring( 65, text.length - 2 ) );
 35359  
 35360  				}
 35361  
 35362  				var font = scope.parse( json );
 35363  
 35364  				if ( onLoad ) onLoad( font );
 35365  
 35366  			}, onProgress, onError );
 35367  
 35368  		},
 35369  
 35370  		parse: function ( json ) {
 35371  
 35372  			return new Font( json );
 35373  
 35374  		}
 35375  
 35376  	} );
 35377  
 35378  	var context;
 35379  
 35380  	var AudioContext = {
 35381  
 35382  		getContext: function () {
 35383  
 35384  			if ( context === undefined ) {
 35385  
 35386  				context = new ( window.AudioContext || window.webkitAudioContext )();
 35387  
 35388  			}
 35389  
 35390  			return context;
 35391  
 35392  		},
 35393  
 35394  		setContext: function ( value ) {
 35395  
 35396  			context = value;
 35397  
 35398  		}
 35399  
 35400  	};
 35401  
 35402  	/**
 35403  	 * @author Reece Aaron Lecrivain / http://reecenotes.com/
 35404  	 */
 35405  
 35406  	function AudioLoader( manager ) {
 35407  
 35408  		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
 35409  
 35410  	}
 35411  
 35412  	Object.assign( AudioLoader.prototype, {
 35413  
 35414  		load: function ( url, onLoad, onProgress, onError ) {
 35415  
 35416  			var loader = new FileLoader( this.manager );
 35417  			loader.setResponseType( 'arraybuffer' );
 35418  			loader.load( url, function ( buffer ) {
 35419  
 35420  				var context = AudioContext.getContext();
 35421  
 35422  				context.decodeAudioData( buffer, function ( audioBuffer ) {
 35423  
 35424  					onLoad( audioBuffer );
 35425  
 35426  				} );
 35427  
 35428  			}, onProgress, onError );
 35429  
 35430  		}
 35431  
 35432  	} );
 35433  
 35434  	/**
 35435  	 * @author abelnation / http://github.com/abelnation
 35436  	 */
 35437  
 35438  	function RectAreaLight ( color, intensity, width, height ) {
 35439  
 35440  		Light.call( this, color, intensity );
 35441  
 35442  		this.type = 'RectAreaLight';
 35443  
 35444  		this.position.set( 0, 1, 0 );
 35445  		this.updateMatrix();
 35446  
 35447  		this.width = ( width !== undefined ) ? width : 10;
 35448  		this.height = ( height !== undefined ) ? height : 10;
 35449  
 35450  		// TODO (abelnation): distance/decay
 35451  
 35452  		// TODO (abelnation): update method for RectAreaLight to update transform to lookat target
 35453  
 35454  		// TODO (abelnation): shadows
 35455  		// this.shadow = new THREE.RectAreaLightShadow( new THREE.PerspectiveCamera( 90, 1, 0.5, 500 ) );
 35456  
 35457  	}
 35458  
 35459  	// TODO (abelnation): RectAreaLight update when light shape is changed
 35460  	RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), {
 35461  
 35462  		constructor: RectAreaLight,
 35463  
 35464  		isRectAreaLight: true,
 35465  
 35466  		copy: function ( source ) {
 35467  
 35468  			Light.prototype.copy.call( this, source );
 35469  
 35470  			this.width = source.width;
 35471  			this.height = source.height;
 35472  
 35473  			// this.shadow = source.shadow.clone();
 35474  
 35475  			return this;
 35476  
 35477  		}
 35478  
 35479  	} );
 35480  
 35481  	/**
 35482  	 * @author mrdoob / http://mrdoob.com/
 35483  	 */
 35484  
 35485  	function StereoCamera() {
 35486  
 35487  		this.type = 'StereoCamera';
 35488  
 35489  		this.aspect = 1;
 35490  
 35491  		this.eyeSep = 0.064;
 35492  
 35493  		this.cameraL = new PerspectiveCamera();
 35494  		this.cameraL.layers.enable( 1 );
 35495  		this.cameraL.matrixAutoUpdate = false;
 35496  
 35497  		this.cameraR = new PerspectiveCamera();
 35498  		this.cameraR.layers.enable( 2 );
 35499  		this.cameraR.matrixAutoUpdate = false;
 35500  
 35501  	}
 35502  
 35503  	Object.assign( StereoCamera.prototype, {
 35504  
 35505  		update: ( function () {
 35506  
 35507  			var instance, focus, fov, aspect, near, far, zoom;
 35508  
 35509  			var eyeRight = new Matrix4();
 35510  			var eyeLeft = new Matrix4();
 35511  
 35512  			return function update( camera ) {
 35513  
 35514  				var needsUpdate = instance !== this || focus !== camera.focus || fov !== camera.fov ||
 35515  													aspect !== camera.aspect * this.aspect || near !== camera.near ||
 35516  													far !== camera.far || zoom !== camera.zoom;
 35517  
 35518  				if ( needsUpdate ) {
 35519  
 35520  					instance = this;
 35521  					focus = camera.focus;
 35522  					fov = camera.fov;
 35523  					aspect = camera.aspect * this.aspect;
 35524  					near = camera.near;
 35525  					far = camera.far;
 35526  					zoom = camera.zoom;
 35527  
 35528  					// Off-axis stereoscopic effect based on
 35529  					// http://paulbourke.net/stereographics/stereorender/
 35530  
 35531  					var projectionMatrix = camera.projectionMatrix.clone();
 35532  					var eyeSep = this.eyeSep / 2;
 35533  					var eyeSepOnProjection = eyeSep * near / focus;
 35534  					var ymax = ( near * Math.tan( _Math.DEG2RAD * fov * 0.5 ) ) / zoom;
 35535  					var xmin, xmax;
 35536  
 35537  					// translate xOffset
 35538  
 35539  					eyeLeft.elements[ 12 ] = - eyeSep;
 35540  					eyeRight.elements[ 12 ] = eyeSep;
 35541  
 35542  					// for left eye
 35543  
 35544  					xmin = - ymax * aspect + eyeSepOnProjection;
 35545  					xmax = ymax * aspect + eyeSepOnProjection;
 35546  
 35547  					projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );
 35548  					projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
 35549  
 35550  					this.cameraL.projectionMatrix.copy( projectionMatrix );
 35551  
 35552  					// for right eye
 35553  
 35554  					xmin = - ymax * aspect - eyeSepOnProjection;
 35555  					xmax = ymax * aspect - eyeSepOnProjection;
 35556  
 35557  					projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );
 35558  					projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
 35559  
 35560  					this.cameraR.projectionMatrix.copy( projectionMatrix );
 35561  
 35562  				}
 35563  
 35564  				this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft );
 35565  				this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight );
 35566  
 35567  			};
 35568  
 35569  		} )()
 35570  
 35571  	} );
 35572  
 35573  	/**
 35574  	 * Camera for rendering cube maps
 35575  	 *	- renders scene into axis-aligned cube
 35576  	 *
 35577  	 * @author alteredq / http://alteredqualia.com/
 35578  	 */
 35579  
 35580  	function CubeCamera( near, far, cubeResolution ) {
 35581  
 35582  		Object3D.call( this );
 35583  
 35584  		this.type = 'CubeCamera';
 35585  
 35586  		var fov = 90, aspect = 1;
 35587  
 35588  		var cameraPX = new PerspectiveCamera( fov, aspect, near, far );
 35589  		cameraPX.up.set( 0, - 1, 0 );
 35590  		cameraPX.lookAt( new Vector3( 1, 0, 0 ) );
 35591  		this.add( cameraPX );
 35592  
 35593  		var cameraNX = new PerspectiveCamera( fov, aspect, near, far );
 35594  		cameraNX.up.set( 0, - 1, 0 );
 35595  		cameraNX.lookAt( new Vector3( - 1, 0, 0 ) );
 35596  		this.add( cameraNX );
 35597  
 35598  		var cameraPY = new PerspectiveCamera( fov, aspect, near, far );
 35599  		cameraPY.up.set( 0, 0, 1 );
 35600  		cameraPY.lookAt( new Vector3( 0, 1, 0 ) );
 35601  		this.add( cameraPY );
 35602  
 35603  		var cameraNY = new PerspectiveCamera( fov, aspect, near, far );
 35604  		cameraNY.up.set( 0, 0, - 1 );
 35605  		cameraNY.lookAt( new Vector3( 0, - 1, 0 ) );
 35606  		this.add( cameraNY );
 35607  
 35608  		var cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
 35609  		cameraPZ.up.set( 0, - 1, 0 );
 35610  		cameraPZ.lookAt( new Vector3( 0, 0, 1 ) );
 35611  		this.add( cameraPZ );
 35612  
 35613  		var cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
 35614  		cameraNZ.up.set( 0, - 1, 0 );
 35615  		cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) );
 35616  		this.add( cameraNZ );
 35617  
 35618  		var options = { format: RGBFormat, magFilter: LinearFilter, minFilter: LinearFilter };
 35619  
 35620  		this.renderTarget = new WebGLRenderTargetCube( cubeResolution, cubeResolution, options );
 35621  
 35622  		this.updateCubeMap = function ( renderer, scene ) {
 35623  
 35624  			if ( this.parent === null ) this.updateMatrixWorld();
 35625  
 35626  			var renderTarget = this.renderTarget;
 35627  			var generateMipmaps = renderTarget.texture.generateMipmaps;
 35628  
 35629  			renderTarget.texture.generateMipmaps = false;
 35630  
 35631  			renderTarget.activeCubeFace = 0;
 35632  			renderer.render( scene, cameraPX, renderTarget );
 35633  
 35634  			renderTarget.activeCubeFace = 1;
 35635  			renderer.render( scene, cameraNX, renderTarget );
 35636  
 35637  			renderTarget.activeCubeFace = 2;
 35638  			renderer.render( scene, cameraPY, renderTarget );
 35639  
 35640  			renderTarget.activeCubeFace = 3;
 35641  			renderer.render( scene, cameraNY, renderTarget );
 35642  
 35643  			renderTarget.activeCubeFace = 4;
 35644  			renderer.render( scene, cameraPZ, renderTarget );
 35645  
 35646  			renderTarget.texture.generateMipmaps = generateMipmaps;
 35647  
 35648  			renderTarget.activeCubeFace = 5;
 35649  			renderer.render( scene, cameraNZ, renderTarget );
 35650  
 35651  			renderer.setRenderTarget( null );
 35652  
 35653  		};
 35654  
 35655  	}
 35656  
 35657  	CubeCamera.prototype = Object.create( Object3D.prototype );
 35658  	CubeCamera.prototype.constructor = CubeCamera;
 35659  
 35660  	/**
 35661  	 * @author mrdoob / http://mrdoob.com/
 35662  	 */
 35663  
 35664  	function AudioListener() {
 35665  
 35666  		Object3D.call( this );
 35667  
 35668  		this.type = 'AudioListener';
 35669  
 35670  		this.context = AudioContext.getContext();
 35671  
 35672  		this.gain = this.context.createGain();
 35673  		this.gain.connect( this.context.destination );
 35674  
 35675  		this.filter = null;
 35676  
 35677  	}
 35678  
 35679  	AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), {
 35680  
 35681  		constructor: AudioListener,
 35682  
 35683  		getInput: function () {
 35684  
 35685  			return this.gain;
 35686  
 35687  		},
 35688  
 35689  		removeFilter: function ( ) {
 35690  
 35691  			if ( this.filter !== null ) {
 35692  
 35693  				this.gain.disconnect( this.filter );
 35694  				this.filter.disconnect( this.context.destination );
 35695  				this.gain.connect( this.context.destination );
 35696  				this.filter = null;
 35697  
 35698  			}
 35699  
 35700  		},
 35701  
 35702  		getFilter: function () {
 35703  
 35704  			return this.filter;
 35705  
 35706  		},
 35707  
 35708  		setFilter: function ( value ) {
 35709  
 35710  			if ( this.filter !== null ) {
 35711  
 35712  				this.gain.disconnect( this.filter );
 35713  				this.filter.disconnect( this.context.destination );
 35714  
 35715  			} else {
 35716  
 35717  				this.gain.disconnect( this.context.destination );
 35718  
 35719  			}
 35720  
 35721  			this.filter = value;
 35722  			this.gain.connect( this.filter );
 35723  			this.filter.connect( this.context.destination );
 35724  
 35725  		},
 35726  
 35727  		getMasterVolume: function () {
 35728  
 35729  			return this.gain.gain.value;
 35730  
 35731  		},
 35732  
 35733  		setMasterVolume: function ( value ) {
 35734  
 35735  			this.gain.gain.value = value;
 35736  
 35737  		},
 35738  
 35739  		updateMatrixWorld: ( function () {
 35740  
 35741  			var position = new Vector3();
 35742  			var quaternion = new Quaternion();
 35743  			var scale = new Vector3();
 35744  
 35745  			var orientation = new Vector3();
 35746  
 35747  			return function updateMatrixWorld( force ) {
 35748  
 35749  				Object3D.prototype.updateMatrixWorld.call( this, force );
 35750  
 35751  				var listener = this.context.listener;
 35752  				var up = this.up;
 35753  
 35754  				this.matrixWorld.decompose( position, quaternion, scale );
 35755  
 35756  				orientation.set( 0, 0, - 1 ).applyQuaternion( quaternion );
 35757  
 35758  				if ( listener.positionX ) {
 35759  
 35760  					listener.positionX.setValueAtTime( position.x, this.context.currentTime );
 35761  					listener.positionY.setValueAtTime( position.y, this.context.currentTime );
 35762  					listener.positionZ.setValueAtTime( position.z, this.context.currentTime );
 35763  					listener.forwardX.setValueAtTime( orientation.x, this.context.currentTime );
 35764  					listener.forwardY.setValueAtTime( orientation.y, this.context.currentTime );
 35765  					listener.forwardZ.setValueAtTime( orientation.z, this.context.currentTime );
 35766  					listener.upX.setValueAtTime( up.x, this.context.currentTime );
 35767  					listener.upY.setValueAtTime( up.y, this.context.currentTime );
 35768  					listener.upZ.setValueAtTime( up.z, this.context.currentTime );
 35769  
 35770  				} else {
 35771  
 35772  					listener.setPosition( position.x, position.y, position.z );
 35773  					listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z );
 35774  
 35775  				}
 35776  
 35777  			};
 35778  
 35779  		} )()
 35780  
 35781  	} );
 35782  
 35783  	/**
 35784  	 * @author mrdoob / http://mrdoob.com/
 35785  	 * @author Reece Aaron Lecrivain / http://reecenotes.com/
 35786  	 */
 35787  
 35788  	function Audio( listener ) {
 35789  
 35790  		Object3D.call( this );
 35791  
 35792  		this.type = 'Audio';
 35793  
 35794  		this.context = listener.context;
 35795  
 35796  		this.gain = this.context.createGain();
 35797  		this.gain.connect( listener.getInput() );
 35798  
 35799  		this.autoplay = false;
 35800  
 35801  		this.buffer = null;
 35802  		this.loop = false;
 35803  		this.startTime = 0;
 35804  		this.playbackRate = 1;
 35805  		this.isPlaying = false;
 35806  		this.hasPlaybackControl = true;
 35807  		this.sourceType = 'empty';
 35808  
 35809  		this.filters = [];
 35810  
 35811  	}
 35812  
 35813  	Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 35814  
 35815  		constructor: Audio,
 35816  
 35817  		getOutput: function () {
 35818  
 35819  			return this.gain;
 35820  
 35821  		},
 35822  
 35823  		setNodeSource: function ( audioNode ) {
 35824  
 35825  			this.hasPlaybackControl = false;
 35826  			this.sourceType = 'audioNode';
 35827  			this.source = audioNode;
 35828  			this.connect();
 35829  
 35830  			return this;
 35831  
 35832  		},
 35833  
 35834  		setBuffer: function ( audioBuffer ) {
 35835  
 35836  			this.buffer = audioBuffer;
 35837  			this.sourceType = 'buffer';
 35838  
 35839  			if ( this.autoplay ) this.play();
 35840  
 35841  			return this;
 35842  
 35843  		},
 35844  
 35845  		play: function () {
 35846  
 35847  			if ( this.isPlaying === true ) {
 35848  
 35849  				console.warn( 'THREE.Audio: Audio is already playing.' );
 35850  				return;
 35851  
 35852  			}
 35853  
 35854  			if ( this.hasPlaybackControl === false ) {
 35855  
 35856  				console.warn( 'THREE.Audio: this Audio has no playback control.' );
 35857  				return;
 35858  
 35859  			}
 35860  
 35861  			var source = this.context.createBufferSource();
 35862  
 35863  			source.buffer = this.buffer;
 35864  			source.loop = this.loop;
 35865  			source.onended = this.onEnded.bind( this );
 35866  			source.playbackRate.setValueAtTime( this.playbackRate, this.startTime );
 35867  			source.start( 0, this.startTime );
 35868  
 35869  			this.isPlaying = true;
 35870  
 35871  			this.source = source;
 35872  
 35873  			return this.connect();
 35874  
 35875  		},
 35876  
 35877  		pause: function () {
 35878  
 35879  			if ( this.hasPlaybackControl === false ) {
 35880  
 35881  				console.warn( 'THREE.Audio: this Audio has no playback control.' );
 35882  				return;
 35883  
 35884  			}
 35885  
 35886  			this.source.stop();
 35887  			this.startTime = this.context.currentTime;
 35888  			this.isPlaying = false;
 35889  
 35890  			return this;
 35891  
 35892  		},
 35893  
 35894  		stop: function () {
 35895  
 35896  			if ( this.hasPlaybackControl === false ) {
 35897  
 35898  				console.warn( 'THREE.Audio: this Audio has no playback control.' );
 35899  				return;
 35900  
 35901  			}
 35902  
 35903  			this.source.stop();
 35904  			this.startTime = 0;
 35905  			this.isPlaying = false;
 35906  
 35907  			return this;
 35908  
 35909  		},
 35910  
 35911  		connect: function () {
 35912  
 35913  			if ( this.filters.length > 0 ) {
 35914  
 35915  				this.source.connect( this.filters[ 0 ] );
 35916  
 35917  				for ( var i = 1, l = this.filters.length; i < l; i ++ ) {
 35918  
 35919  					this.filters[ i - 1 ].connect( this.filters[ i ] );
 35920  
 35921  				}
 35922  
 35923  				this.filters[ this.filters.length - 1 ].connect( this.getOutput() );
 35924  
 35925  			} else {
 35926  
 35927  				this.source.connect( this.getOutput() );
 35928  
 35929  			}
 35930  
 35931  			return this;
 35932  
 35933  		},
 35934  
 35935  		disconnect: function () {
 35936  
 35937  			if ( this.filters.length > 0 ) {
 35938  
 35939  				this.source.disconnect( this.filters[ 0 ] );
 35940  
 35941  				for ( var i = 1, l = this.filters.length; i < l; i ++ ) {
 35942  
 35943  					this.filters[ i - 1 ].disconnect( this.filters[ i ] );
 35944  
 35945  				}
 35946  
 35947  				this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );
 35948  
 35949  			} else {
 35950  
 35951  				this.source.disconnect( this.getOutput() );
 35952  
 35953  			}
 35954  
 35955  			return this;
 35956  
 35957  		},
 35958  
 35959  		getFilters: function () {
 35960  
 35961  			return this.filters;
 35962  
 35963  		},
 35964  
 35965  		setFilters: function ( value ) {
 35966  
 35967  			if ( ! value ) value = [];
 35968  
 35969  			if ( this.isPlaying === true ) {
 35970  
 35971  				this.disconnect();
 35972  				this.filters = value;
 35973  				this.connect();
 35974  
 35975  			} else {
 35976  
 35977  				this.filters = value;
 35978  
 35979  			}
 35980  
 35981  			return this;
 35982  
 35983  		},
 35984  
 35985  		getFilter: function () {
 35986  
 35987  			return this.getFilters()[ 0 ];
 35988  
 35989  		},
 35990  
 35991  		setFilter: function ( filter ) {
 35992  
 35993  			return this.setFilters( filter ? [ filter ] : [] );
 35994  
 35995  		},
 35996  
 35997  		setPlaybackRate: function ( value ) {
 35998  
 35999  			if ( this.hasPlaybackControl === false ) {
 36000  
 36001  				console.warn( 'THREE.Audio: this Audio has no playback control.' );
 36002  				return;
 36003  
 36004  			}
 36005  
 36006  			this.playbackRate = value;
 36007  
 36008  			if ( this.isPlaying === true ) {
 36009  
 36010  				this.source.playbackRate.setValueAtTime( this.playbackRate, this.context.currentTime );
 36011  
 36012  			}
 36013  
 36014  			return this;
 36015  
 36016  		},
 36017  
 36018  		getPlaybackRate: function () {
 36019  
 36020  			return this.playbackRate;
 36021  
 36022  		},
 36023  
 36024  		onEnded: function () {
 36025  
 36026  			this.isPlaying = false;
 36027  
 36028  		},
 36029  
 36030  		getLoop: function () {
 36031  
 36032  			if ( this.hasPlaybackControl === false ) {
 36033  
 36034  				console.warn( 'THREE.Audio: this Audio has no playback control.' );
 36035  				return false;
 36036  
 36037  			}
 36038  
 36039  			return this.loop;
 36040  
 36041  		},
 36042  
 36043  		setLoop: function ( value ) {
 36044  
 36045  			if ( this.hasPlaybackControl === false ) {
 36046  
 36047  				console.warn( 'THREE.Audio: this Audio has no playback control.' );
 36048  				return;
 36049  
 36050  			}
 36051  
 36052  			this.loop = value;
 36053  
 36054  			if ( this.isPlaying === true ) {
 36055  
 36056  				this.source.loop = this.loop;
 36057  
 36058  			}
 36059  
 36060  			return this;
 36061  
 36062  		},
 36063  
 36064  		getVolume: function () {
 36065  
 36066  			return this.gain.gain.value;
 36067  
 36068  		},
 36069  
 36070  
 36071  		setVolume: function ( value ) {
 36072  
 36073  			this.gain.gain.value = value;
 36074  
 36075  			return this;
 36076  
 36077  		}
 36078  
 36079  	} );
 36080  
 36081  	/**
 36082  	 * @author mrdoob / http://mrdoob.com/
 36083  	 */
 36084  
 36085  	function PositionalAudio( listener ) {
 36086  
 36087  		Audio.call( this, listener );
 36088  
 36089  		this.panner = this.context.createPanner();
 36090  		this.panner.connect( this.gain );
 36091  
 36092  	}
 36093  
 36094  	PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), {
 36095  
 36096  		constructor: PositionalAudio,
 36097  
 36098  		getOutput: function () {
 36099  
 36100  			return this.panner;
 36101  
 36102  		},
 36103  
 36104  		getRefDistance: function () {
 36105  
 36106  			return this.panner.refDistance;
 36107  
 36108  		},
 36109  
 36110  		setRefDistance: function ( value ) {
 36111  
 36112  			this.panner.refDistance = value;
 36113  
 36114  		},
 36115  
 36116  		getRolloffFactor: function () {
 36117  
 36118  			return this.panner.rolloffFactor;
 36119  
 36120  		},
 36121  
 36122  		setRolloffFactor: function ( value ) {
 36123  
 36124  			this.panner.rolloffFactor = value;
 36125  
 36126  		},
 36127  
 36128  		getDistanceModel: function () {
 36129  
 36130  			return this.panner.distanceModel;
 36131  
 36132  		},
 36133  
 36134  		setDistanceModel: function ( value ) {
 36135  
 36136  			this.panner.distanceModel = value;
 36137  
 36138  		},
 36139  
 36140  		getMaxDistance: function () {
 36141  
 36142  			return this.panner.maxDistance;
 36143  
 36144  		},
 36145  
 36146  		setMaxDistance: function ( value ) {
 36147  
 36148  			this.panner.maxDistance = value;
 36149  
 36150  		},
 36151  
 36152  		updateMatrixWorld: ( function () {
 36153  
 36154  			var position = new Vector3();
 36155  
 36156  			return function updateMatrixWorld( force ) {
 36157  
 36158  				Object3D.prototype.updateMatrixWorld.call( this, force );
 36159  
 36160  				position.setFromMatrixPosition( this.matrixWorld );
 36161  
 36162  				this.panner.setPosition( position.x, position.y, position.z );
 36163  
 36164  			};
 36165  
 36166  		} )()
 36167  
 36168  
 36169  	} );
 36170  
 36171  	/**
 36172  	 * @author mrdoob / http://mrdoob.com/
 36173  	 */
 36174  
 36175  	function AudioAnalyser( audio, fftSize ) {
 36176  
 36177  		this.analyser = audio.context.createAnalyser();
 36178  		this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048;
 36179  
 36180  		this.data = new Uint8Array( this.analyser.frequencyBinCount );
 36181  
 36182  		audio.getOutput().connect( this.analyser );
 36183  
 36184  	}
 36185  
 36186  	Object.assign( AudioAnalyser.prototype, {
 36187  
 36188  		getFrequencyData: function () {
 36189  
 36190  			this.analyser.getByteFrequencyData( this.data );
 36191  
 36192  			return this.data;
 36193  
 36194  		},
 36195  
 36196  		getAverageFrequency: function () {
 36197  
 36198  			var value = 0, data = this.getFrequencyData();
 36199  
 36200  			for ( var i = 0; i < data.length; i ++ ) {
 36201  
 36202  				value += data[ i ];
 36203  
 36204  			}
 36205  
 36206  			return value / data.length;
 36207  
 36208  		}
 36209  
 36210  	} );
 36211  
 36212  	/**
 36213  	 *
 36214  	 * Buffered scene graph property that allows weighted accumulation.
 36215  	 *
 36216  	 *
 36217  	 * @author Ben Houston / http://clara.io/
 36218  	 * @author David Sarno / http://lighthaus.us/
 36219  	 * @author tschw
 36220  	 */
 36221  
 36222  	function PropertyMixer( binding, typeName, valueSize ) {
 36223  
 36224  		this.binding = binding;
 36225  		this.valueSize = valueSize;
 36226  
 36227  		var bufferType = Float64Array,
 36228  			mixFunction;
 36229  
 36230  		switch ( typeName ) {
 36231  
 36232  			case 'quaternion':
 36233  				mixFunction = this._slerp;
 36234  				break;
 36235  
 36236  			case 'string':
 36237  			case 'bool':
 36238  				bufferType = Array;
 36239  				mixFunction = this._select;
 36240  				break;
 36241  
 36242  			default:
 36243  				mixFunction = this._lerp;
 36244  
 36245  		}
 36246  
 36247  		this.buffer = new bufferType( valueSize * 4 );
 36248  		// layout: [ incoming | accu0 | accu1 | orig ]
 36249  		//
 36250  		// interpolators can use .buffer as their .result
 36251  		// the data then goes to 'incoming'
 36252  		//
 36253  		// 'accu0' and 'accu1' are used frame-interleaved for
 36254  		// the cumulative result and are compared to detect
 36255  		// changes
 36256  		//
 36257  		// 'orig' stores the original state of the property
 36258  
 36259  		this._mixBufferRegion = mixFunction;
 36260  
 36261  		this.cumulativeWeight = 0;
 36262  
 36263  		this.useCount = 0;
 36264  		this.referenceCount = 0;
 36265  
 36266  	}
 36267  
 36268  	PropertyMixer.prototype = {
 36269  
 36270  		constructor: PropertyMixer,
 36271  
 36272  		// accumulate data in the 'incoming' region into 'accu<i>'
 36273  		accumulate: function( accuIndex, weight ) {
 36274  
 36275  			// note: happily accumulating nothing when weight = 0, the caller knows
 36276  			// the weight and shouldn't have made the call in the first place
 36277  
 36278  			var buffer = this.buffer,
 36279  				stride = this.valueSize,
 36280  				offset = accuIndex * stride + stride,
 36281  
 36282  				currentWeight = this.cumulativeWeight;
 36283  
 36284  			if ( currentWeight === 0 ) {
 36285  
 36286  				// accuN := incoming * weight
 36287  
 36288  				for ( var i = 0; i !== stride; ++ i ) {
 36289  
 36290  					buffer[ offset + i ] = buffer[ i ];
 36291  
 36292  				}
 36293  
 36294  				currentWeight = weight;
 36295  
 36296  			} else {
 36297  
 36298  				// accuN := accuN + incoming * weight
 36299  
 36300  				currentWeight += weight;
 36301  				var mix = weight / currentWeight;
 36302  				this._mixBufferRegion( buffer, offset, 0, mix, stride );
 36303  
 36304  			}
 36305  
 36306  			this.cumulativeWeight = currentWeight;
 36307  
 36308  		},
 36309  
 36310  		// apply the state of 'accu<i>' to the binding when accus differ
 36311  		apply: function( accuIndex ) {
 36312  
 36313  			var stride = this.valueSize,
 36314  				buffer = this.buffer,
 36315  				offset = accuIndex * stride + stride,
 36316  
 36317  				weight = this.cumulativeWeight,
 36318  
 36319  				binding = this.binding;
 36320  
 36321  			this.cumulativeWeight = 0;
 36322  
 36323  			if ( weight < 1 ) {
 36324  
 36325  				// accuN := accuN + original * ( 1 - cumulativeWeight )
 36326  
 36327  				var originalValueOffset = stride * 3;
 36328  
 36329  				this._mixBufferRegion(
 36330  						buffer, offset, originalValueOffset, 1 - weight, stride );
 36331  
 36332  			}
 36333  
 36334  			for ( var i = stride, e = stride + stride; i !== e; ++ i ) {
 36335  
 36336  				if ( buffer[ i ] !== buffer[ i + stride ] ) {
 36337  
 36338  					// value has changed -> update scene graph
 36339  
 36340  					binding.setValue( buffer, offset );
 36341  					break;
 36342  
 36343  				}
 36344  
 36345  			}
 36346  
 36347  		},
 36348  
 36349  		// remember the state of the bound property and copy it to both accus
 36350  		saveOriginalState: function() {
 36351  
 36352  			var binding = this.binding;
 36353  
 36354  			var buffer = this.buffer,
 36355  				stride = this.valueSize,
 36356  
 36357  				originalValueOffset = stride * 3;
 36358  
 36359  			binding.getValue( buffer, originalValueOffset );
 36360  
 36361  			// accu[0..1] := orig -- initially detect changes against the original
 36362  			for ( var i = stride, e = originalValueOffset; i !== e; ++ i ) {
 36363  
 36364  				buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];
 36365  
 36366  			}
 36367  
 36368  			this.cumulativeWeight = 0;
 36369  
 36370  		},
 36371  
 36372  		// apply the state previously taken via 'saveOriginalState' to the binding
 36373  		restoreOriginalState: function() {
 36374  
 36375  			var originalValueOffset = this.valueSize * 3;
 36376  			this.binding.setValue( this.buffer, originalValueOffset );
 36377  
 36378  		},
 36379  
 36380  
 36381  		// mix functions
 36382  
 36383  		_select: function( buffer, dstOffset, srcOffset, t, stride ) {
 36384  
 36385  			if ( t >= 0.5 ) {
 36386  
 36387  				for ( var i = 0; i !== stride; ++ i ) {
 36388  
 36389  					buffer[ dstOffset + i ] = buffer[ srcOffset + i ];
 36390  
 36391  				}
 36392  
 36393  			}
 36394  
 36395  		},
 36396  
 36397  		_slerp: function( buffer, dstOffset, srcOffset, t, stride ) {
 36398  
 36399  			Quaternion.slerpFlat( buffer, dstOffset,
 36400  					buffer, dstOffset, buffer, srcOffset, t );
 36401  
 36402  		},
 36403  
 36404  		_lerp: function( buffer, dstOffset, srcOffset, t, stride ) {
 36405  
 36406  			var s = 1 - t;
 36407  
 36408  			for ( var i = 0; i !== stride; ++ i ) {
 36409  
 36410  				var j = dstOffset + i;
 36411  
 36412  				buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;
 36413  
 36414  			}
 36415  
 36416  		}
 36417  
 36418  	};
 36419  
 36420  	/**
 36421  	 *
 36422  	 * A reference to a real property in the scene graph.
 36423  	 *
 36424  	 *
 36425  	 * @author Ben Houston / http://clara.io/
 36426  	 * @author David Sarno / http://lighthaus.us/
 36427  	 * @author tschw
 36428  	 */
 36429  
 36430  	function PropertyBinding( rootNode, path, parsedPath ) {
 36431  
 36432  		this.path = path;
 36433  		this.parsedPath = parsedPath ||
 36434  				PropertyBinding.parseTrackName( path );
 36435  
 36436  		this.node = PropertyBinding.findNode(
 36437  				rootNode, this.parsedPath.nodeName ) || rootNode;
 36438  
 36439  		this.rootNode = rootNode;
 36440  
 36441  	}
 36442  
 36443  	PropertyBinding.prototype = {
 36444  
 36445  		constructor: PropertyBinding,
 36446  
 36447  		getValue: function getValue_unbound( targetArray, offset ) {
 36448  
 36449  			this.bind();
 36450  			this.getValue( targetArray, offset );
 36451  
 36452  			// Note: This class uses a State pattern on a per-method basis:
 36453  			// 'bind' sets 'this.getValue' / 'setValue' and shadows the
 36454  			// prototype version of these methods with one that represents
 36455  			// the bound state. When the property is not found, the methods
 36456  			// become no-ops.
 36457  
 36458  		},
 36459  
 36460  		setValue: function getValue_unbound( sourceArray, offset ) {
 36461  
 36462  			this.bind();
 36463  			this.setValue( sourceArray, offset );
 36464  
 36465  		},
 36466  
 36467  		// create getter / setter pair for a property in the scene graph
 36468  		bind: function() {
 36469  
 36470  			var targetObject = this.node,
 36471  				parsedPath = this.parsedPath,
 36472  
 36473  				objectName = parsedPath.objectName,
 36474  				propertyName = parsedPath.propertyName,
 36475  				propertyIndex = parsedPath.propertyIndex;
 36476  
 36477  			if ( ! targetObject ) {
 36478  
 36479  				targetObject = PropertyBinding.findNode(
 36480  						this.rootNode, parsedPath.nodeName ) || this.rootNode;
 36481  
 36482  				this.node = targetObject;
 36483  
 36484  			}
 36485  
 36486  			// set fail state so we can just 'return' on error
 36487  			this.getValue = this._getValue_unavailable;
 36488  			this.setValue = this._setValue_unavailable;
 36489  
 36490  	 		// ensure there is a value node
 36491  			if ( ! targetObject ) {
 36492  
 36493  				console.error( "  trying to update node for track: " + this.path + " but it wasn't found." );
 36494  				return;
 36495  
 36496  			}
 36497  
 36498  			if ( objectName ) {
 36499  
 36500  				var objectIndex = parsedPath.objectIndex;
 36501  
 36502  				// special cases were we need to reach deeper into the hierarchy to get the face materials....
 36503  				switch ( objectName ) {
 36504  
 36505  					case 'materials':
 36506  
 36507  						if ( ! targetObject.material ) {
 36508  
 36509  							console.error( '  can not bind to material as node does not have a material', this );
 36510  							return;
 36511  
 36512  						}
 36513  
 36514  						if ( ! targetObject.material.materials ) {
 36515  
 36516  							console.error( '  can not bind to material.materials as node.material does not have a materials array', this );
 36517  							return;
 36518  
 36519  						}
 36520  
 36521  						targetObject = targetObject.material.materials;
 36522  
 36523  						break;
 36524  
 36525  					case 'bones':
 36526  
 36527  						if ( ! targetObject.skeleton ) {
 36528  
 36529  							console.error( '  can not bind to bones as node does not have a skeleton', this );
 36530  							return;
 36531  
 36532  						}
 36533  
 36534  						// potential future optimization: skip this if propertyIndex is already an integer
 36535  						// and convert the integer string to a true integer.
 36536  
 36537  						targetObject = targetObject.skeleton.bones;
 36538  
 36539  						// support resolving morphTarget names into indices.
 36540  						for ( var i = 0; i < targetObject.length; i ++ ) {
 36541  
 36542  							if ( targetObject[ i ].name === objectIndex ) {
 36543  
 36544  								objectIndex = i;
 36545  								break;
 36546  
 36547  							}
 36548  
 36549  						}
 36550  
 36551  						break;
 36552  
 36553  					default:
 36554  
 36555  						if ( targetObject[ objectName ] === undefined ) {
 36556  
 36557  							console.error( '  can not bind to objectName of node, undefined', this );
 36558  							return;
 36559  
 36560  						}
 36561  
 36562  						targetObject = targetObject[ objectName ];
 36563  
 36564  				}
 36565  
 36566  
 36567  				if ( objectIndex !== undefined ) {
 36568  
 36569  					if ( targetObject[ objectIndex ] === undefined ) {
 36570  
 36571  						console.error( "  trying to bind to objectIndex of objectName, but is undefined:", this, targetObject );
 36572  						return;
 36573  
 36574  					}
 36575  
 36576  					targetObject = targetObject[ objectIndex ];
 36577  
 36578  				}
 36579  
 36580  			}
 36581  
 36582  			// resolve property
 36583  			var nodeProperty = targetObject[ propertyName ];
 36584  
 36585  			if ( nodeProperty === undefined ) {
 36586  
 36587  				var nodeName = parsedPath.nodeName;
 36588  
 36589  				console.error( "  trying to update property for track: " + nodeName +
 36590  						'.' + propertyName + " but it wasn't found.", targetObject );
 36591  				return;
 36592  
 36593  			}
 36594  
 36595  			// determine versioning scheme
 36596  			var versioning = this.Versioning.None;
 36597  
 36598  			if ( targetObject.needsUpdate !== undefined ) { // material
 36599  
 36600  				versioning = this.Versioning.NeedsUpdate;
 36601  				this.targetObject = targetObject;
 36602  
 36603  			} else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
 36604  
 36605  				versioning = this.Versioning.MatrixWorldNeedsUpdate;
 36606  				this.targetObject = targetObject;
 36607  
 36608  			}
 36609  
 36610  			// determine how the property gets bound
 36611  			var bindingType = this.BindingType.Direct;
 36612  
 36613  			if ( propertyIndex !== undefined ) {
 36614  				// access a sub element of the property array (only primitives are supported right now)
 36615  
 36616  				if ( propertyName === "morphTargetInfluences" ) {
 36617  					// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
 36618  
 36619  					// support resolving morphTarget names into indices.
 36620  					if ( ! targetObject.geometry ) {
 36621  
 36622  						console.error( '  can not bind to morphTargetInfluences becasuse node does not have a geometry', this );
 36623  						return;
 36624  
 36625  					}
 36626  
 36627  					if ( ! targetObject.geometry.morphTargets ) {
 36628  
 36629  						console.error( '  can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets', this );
 36630  						return;
 36631  
 36632  					}
 36633  
 36634  					for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) {
 36635  
 36636  						if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) {
 36637  
 36638  							propertyIndex = i;
 36639  							break;
 36640  
 36641  						}
 36642  
 36643  					}
 36644  
 36645  				}
 36646  
 36647  				bindingType = this.BindingType.ArrayElement;
 36648  
 36649  				this.resolvedProperty = nodeProperty;
 36650  				this.propertyIndex = propertyIndex;
 36651  
 36652  			} else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
 36653  				// must use copy for Object3D.Euler/Quaternion
 36654  
 36655  				bindingType = this.BindingType.HasFromToArray;
 36656  
 36657  				this.resolvedProperty = nodeProperty;
 36658  
 36659  			} else if ( nodeProperty.length !== undefined ) {
 36660  
 36661  				bindingType = this.BindingType.EntireArray;
 36662  
 36663  				this.resolvedProperty = nodeProperty;
 36664  
 36665  			} else {
 36666  
 36667  				this.propertyName = propertyName;
 36668  
 36669  			}
 36670  
 36671  			// select getter / setter
 36672  			this.getValue = this.GetterByBindingType[ bindingType ];
 36673  			this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
 36674  
 36675  		},
 36676  
 36677  		unbind: function() {
 36678  
 36679  			this.node = null;
 36680  
 36681  			// back to the prototype version of getValue / setValue
 36682  			// note: avoiding to mutate the shape of 'this' via 'delete'
 36683  			this.getValue = this._getValue_unbound;
 36684  			this.setValue = this._setValue_unbound;
 36685  
 36686  		}
 36687  
 36688  	};
 36689  
 36690  	Object.assign( PropertyBinding.prototype, { // prototype, continued
 36691  
 36692  		// these are used to "bind" a nonexistent property
 36693  		_getValue_unavailable: function() {},
 36694  		_setValue_unavailable: function() {},
 36695  
 36696  		// initial state of these methods that calls 'bind'
 36697  		_getValue_unbound: PropertyBinding.prototype.getValue,
 36698  		_setValue_unbound: PropertyBinding.prototype.setValue,
 36699  
 36700  		BindingType: {
 36701  			Direct: 0,
 36702  			EntireArray: 1,
 36703  			ArrayElement: 2,
 36704  			HasFromToArray: 3
 36705  		},
 36706  
 36707  		Versioning: {
 36708  			None: 0,
 36709  			NeedsUpdate: 1,
 36710  			MatrixWorldNeedsUpdate: 2
 36711  		},
 36712  
 36713  		GetterByBindingType: [
 36714  
 36715  			function getValue_direct( buffer, offset ) {
 36716  
 36717  				buffer[ offset ] = this.node[ this.propertyName ];
 36718  
 36719  			},
 36720  
 36721  			function getValue_array( buffer, offset ) {
 36722  
 36723  				var source = this.resolvedProperty;
 36724  
 36725  				for ( var i = 0, n = source.length; i !== n; ++ i ) {
 36726  
 36727  					buffer[ offset ++ ] = source[ i ];
 36728  
 36729  				}
 36730  
 36731  			},
 36732  
 36733  			function getValue_arrayElement( buffer, offset ) {
 36734  
 36735  				buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
 36736  
 36737  			},
 36738  
 36739  			function getValue_toArray( buffer, offset ) {
 36740  
 36741  				this.resolvedProperty.toArray( buffer, offset );
 36742  
 36743  			}
 36744  
 36745  		],
 36746  
 36747  		SetterByBindingTypeAndVersioning: [
 36748  
 36749  			[
 36750  				// Direct
 36751  
 36752  				function setValue_direct( buffer, offset ) {
 36753  
 36754  					this.node[ this.propertyName ] = buffer[ offset ];
 36755  
 36756  				},
 36757  
 36758  				function setValue_direct_setNeedsUpdate( buffer, offset ) {
 36759  
 36760  					this.node[ this.propertyName ] = buffer[ offset ];
 36761  					this.targetObject.needsUpdate = true;
 36762  
 36763  				},
 36764  
 36765  				function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {
 36766  
 36767  					this.node[ this.propertyName ] = buffer[ offset ];
 36768  					this.targetObject.matrixWorldNeedsUpdate = true;
 36769  
 36770  				}
 36771  
 36772  			], [
 36773  
 36774  				// EntireArray
 36775  
 36776  				function setValue_array( buffer, offset ) {
 36777  
 36778  					var dest = this.resolvedProperty;
 36779  
 36780  					for ( var i = 0, n = dest.length; i !== n; ++ i ) {
 36781  
 36782  						dest[ i ] = buffer[ offset ++ ];
 36783  
 36784  					}
 36785  
 36786  				},
 36787  
 36788  				function setValue_array_setNeedsUpdate( buffer, offset ) {
 36789  
 36790  					var dest = this.resolvedProperty;
 36791  
 36792  					for ( var i = 0, n = dest.length; i !== n; ++ i ) {
 36793  
 36794  						dest[ i ] = buffer[ offset ++ ];
 36795  
 36796  					}
 36797  
 36798  					this.targetObject.needsUpdate = true;
 36799  
 36800  				},
 36801  
 36802  				function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {
 36803  
 36804  					var dest = this.resolvedProperty;
 36805  
 36806  					for ( var i = 0, n = dest.length; i !== n; ++ i ) {
 36807  
 36808  						dest[ i ] = buffer[ offset ++ ];
 36809  
 36810  					}
 36811  
 36812  					this.targetObject.matrixWorldNeedsUpdate = true;
 36813  
 36814  				}
 36815  
 36816  			], [
 36817  
 36818  				// ArrayElement
 36819  
 36820  				function setValue_arrayElement( buffer, offset ) {
 36821  
 36822  					this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
 36823  
 36824  				},
 36825  
 36826  				function setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
 36827  
 36828  					this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
 36829  					this.targetObject.needsUpdate = true;
 36830  
 36831  				},
 36832  
 36833  				function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
 36834  
 36835  					this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
 36836  					this.targetObject.matrixWorldNeedsUpdate = true;
 36837  
 36838  				}
 36839  
 36840  			], [
 36841  
 36842  				// HasToFromArray
 36843  
 36844  				function setValue_fromArray( buffer, offset ) {
 36845  
 36846  					this.resolvedProperty.fromArray( buffer, offset );
 36847  
 36848  				},
 36849  
 36850  				function setValue_fromArray_setNeedsUpdate( buffer, offset ) {
 36851  
 36852  					this.resolvedProperty.fromArray( buffer, offset );
 36853  					this.targetObject.needsUpdate = true;
 36854  
 36855  				},
 36856  
 36857  				function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {
 36858  
 36859  					this.resolvedProperty.fromArray( buffer, offset );
 36860  					this.targetObject.matrixWorldNeedsUpdate = true;
 36861  
 36862  				}
 36863  
 36864  			]
 36865  
 36866  		]
 36867  
 36868  	} );
 36869  
 36870  	PropertyBinding.Composite =
 36871  			function( targetGroup, path, optionalParsedPath ) {
 36872  
 36873  		var parsedPath = optionalParsedPath ||
 36874  				PropertyBinding.parseTrackName( path );
 36875  
 36876  		this._targetGroup = targetGroup;
 36877  		this._bindings = targetGroup.subscribe_( path, parsedPath );
 36878  
 36879  	};
 36880  
 36881  	PropertyBinding.Composite.prototype = {
 36882  
 36883  		constructor: PropertyBinding.Composite,
 36884  
 36885  		getValue: function( array, offset ) {
 36886  
 36887  			this.bind(); // bind all binding
 36888  
 36889  			var firstValidIndex = this._targetGroup.nCachedObjects_,
 36890  				binding = this._bindings[ firstValidIndex ];
 36891  
 36892  			// and only call .getValue on the first
 36893  			if ( binding !== undefined ) binding.getValue( array, offset );
 36894  
 36895  		},
 36896  
 36897  		setValue: function( array, offset ) {
 36898  
 36899  			var bindings = this._bindings;
 36900  
 36901  			for ( var i = this._targetGroup.nCachedObjects_,
 36902  					n = bindings.length; i !== n; ++ i ) {
 36903  
 36904  				bindings[ i ].setValue( array, offset );
 36905  
 36906  			}
 36907  
 36908  		},
 36909  
 36910  		bind: function() {
 36911  
 36912  			var bindings = this._bindings;
 36913  
 36914  			for ( var i = this._targetGroup.nCachedObjects_,
 36915  					n = bindings.length; i !== n; ++ i ) {
 36916  
 36917  				bindings[ i ].bind();
 36918  
 36919  			}
 36920  
 36921  		},
 36922  
 36923  		unbind: function() {
 36924  
 36925  			var bindings = this._bindings;
 36926  
 36927  			for ( var i = this._targetGroup.nCachedObjects_,
 36928  					n = bindings.length; i !== n; ++ i ) {
 36929  
 36930  				bindings[ i ].unbind();
 36931  
 36932  			}
 36933  
 36934  		}
 36935  
 36936  	};
 36937  
 36938  	PropertyBinding.create = function( root, path, parsedPath ) {
 36939  
 36940  		if ( ! ( root && root.isAnimationObjectGroup ) ) {
 36941  
 36942  			return new PropertyBinding( root, path, parsedPath );
 36943  
 36944  		} else {
 36945  
 36946  			return new PropertyBinding.Composite( root, path, parsedPath );
 36947  
 36948  		}
 36949  
 36950  	};
 36951  
 36952  	PropertyBinding.parseTrackName = function( trackName ) {
 36953  
 36954  		// matches strings in the form of:
 36955  		//    nodeName.property
 36956  		//    nodeName.property[accessor]
 36957  		//    nodeName.material.property[accessor]
 36958  		//    uuid.property[accessor]
 36959  		//    uuid.objectName[objectIndex].propertyName[propertyIndex]
 36960  		//    parentName/nodeName.property
 36961  		//    parentName/parentName/nodeName.property[index]
 36962  		//    .bone[Armature.DEF_cog].position
 36963  		//    scene:helium_balloon_model:helium_balloon_model.position
 36964  		// created and tested via https://regex101.com/#javascript
 36965  
 36966  		var re = /^((?:[\w-]+[\/:])*)([\w-]+)?(?:\.([\w-]+)(?:\[(.+)\])?)?\.([\w-]+)(?:\[(.+)\])?$/;
 36967  		var matches = re.exec( trackName );
 36968  
 36969  		if ( ! matches ) {
 36970  
 36971  			throw new Error( "cannot parse trackName at all: " + trackName );
 36972  
 36973  		}
 36974  
 36975  		var results = {
 36976  			// directoryName: matches[ 1 ], // (tschw) currently unused
 36977  			nodeName: matches[ 2 ], 	// allowed to be null, specified root node.
 36978  			objectName: matches[ 3 ],
 36979  			objectIndex: matches[ 4 ],
 36980  			propertyName: matches[ 5 ],
 36981  			propertyIndex: matches[ 6 ]	// allowed to be null, specifies that the whole property is set.
 36982  		};
 36983  
 36984  		if ( results.propertyName === null || results.propertyName.length === 0 ) {
 36985  
 36986  			throw new Error( "can not parse propertyName from trackName: " + trackName );
 36987  
 36988  		}
 36989  
 36990  		return results;
 36991  
 36992  	};
 36993  
 36994  	PropertyBinding.findNode = function( root, nodeName ) {
 36995  
 36996  		if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === -1 || nodeName === root.name || nodeName === root.uuid ) {
 36997  
 36998  			return root;
 36999  
 37000  		}
 37001  
 37002  		// search into skeleton bones.
 37003  		if ( root.skeleton ) {
 37004  
 37005  			var searchSkeleton = function( skeleton ) {
 37006  
 37007  				for( var i = 0; i < skeleton.bones.length; i ++ ) {
 37008  
 37009  					var bone = skeleton.bones[ i ];
 37010  
 37011  					if ( bone.name === nodeName ) {
 37012  
 37013  						return bone;
 37014  
 37015  					}
 37016  				}
 37017  
 37018  				return null;
 37019  
 37020  			};
 37021  
 37022  			var bone = searchSkeleton( root.skeleton );
 37023  
 37024  			if ( bone ) {
 37025  
 37026  				return bone;
 37027  
 37028  			}
 37029  		}
 37030  
 37031  		// search into node subtree.
 37032  		if ( root.children ) {
 37033  
 37034  			var searchNodeSubtree = function( children ) {
 37035  
 37036  				for( var i = 0; i < children.length; i ++ ) {
 37037  
 37038  					var childNode = children[ i ];
 37039  
 37040  					if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
 37041  
 37042  						return childNode;
 37043  
 37044  					}
 37045  
 37046  					var result = searchNodeSubtree( childNode.children );
 37047  
 37048  					if ( result ) return result;
 37049  
 37050  				}
 37051  
 37052  				return null;
 37053  
 37054  			};
 37055  
 37056  			var subTreeNode = searchNodeSubtree( root.children );
 37057  
 37058  			if ( subTreeNode ) {
 37059  
 37060  				return subTreeNode;
 37061  
 37062  			}
 37063  
 37064  		}
 37065  
 37066  		return null;
 37067  
 37068  	};
 37069  
 37070  	/**
 37071  	 *
 37072  	 * A group of objects that receives a shared animation state.
 37073  	 *
 37074  	 * Usage:
 37075  	 *
 37076  	 * 	-	Add objects you would otherwise pass as 'root' to the
 37077  	 * 		constructor or the .clipAction method of AnimationMixer.
 37078  	 *
 37079  	 * 	-	Instead pass this object as 'root'.
 37080  	 *
 37081  	 * 	-	You can also add and remove objects later when the mixer
 37082  	 * 		is running.
 37083  	 *
 37084  	 * Note:
 37085  	 *
 37086  	 *  	Objects of this class appear as one object to the mixer,
 37087  	 *  	so cache control of the individual objects must be done
 37088  	 *  	on the group.
 37089  	 *
 37090  	 * Limitation:
 37091  	 *
 37092  	 * 	- 	The animated properties must be compatible among the
 37093  	 * 		all objects in the group.
 37094  	 *
 37095  	 *  -	A single property can either be controlled through a
 37096  	 *  	target group or directly, but not both.
 37097  	 *
 37098  	 * @author tschw
 37099  	 */
 37100  
 37101  	function AnimationObjectGroup( var_args ) {
 37102  
 37103  		this.uuid = _Math.generateUUID();
 37104  
 37105  		// cached objects followed by the active ones
 37106  		this._objects = Array.prototype.slice.call( arguments );
 37107  
 37108  		this.nCachedObjects_ = 0;			// threshold
 37109  		// note: read by PropertyBinding.Composite
 37110  
 37111  		var indices = {};
 37112  		this._indicesByUUID = indices;		// for bookkeeping
 37113  
 37114  		for ( var i = 0, n = arguments.length; i !== n; ++ i ) {
 37115  
 37116  			indices[ arguments[ i ].uuid ] = i;
 37117  
 37118  		}
 37119  
 37120  		this._paths = [];					// inside: string
 37121  		this._parsedPaths = [];				// inside: { we don't care, here }
 37122  		this._bindings = []; 				// inside: Array< PropertyBinding >
 37123  		this._bindingsIndicesByPath = {}; 	// inside: indices in these arrays
 37124  
 37125  		var scope = this;
 37126  
 37127  		this.stats = {
 37128  
 37129  			objects: {
 37130  				get total() { return scope._objects.length; },
 37131  				get inUse() { return this.total - scope.nCachedObjects_;  }
 37132  			},
 37133  
 37134  			get bindingsPerObject() { return scope._bindings.length; }
 37135  
 37136  		};
 37137  
 37138  	}
 37139  
 37140  	AnimationObjectGroup.prototype = {
 37141  
 37142  		constructor: AnimationObjectGroup,
 37143  
 37144  		isAnimationObjectGroup: true,
 37145  
 37146  		add: function( var_args ) {
 37147  
 37148  			var objects = this._objects,
 37149  				nObjects = objects.length,
 37150  				nCachedObjects = this.nCachedObjects_,
 37151  				indicesByUUID = this._indicesByUUID,
 37152  				paths = this._paths,
 37153  				parsedPaths = this._parsedPaths,
 37154  				bindings = this._bindings,
 37155  				nBindings = bindings.length;
 37156  
 37157  			for ( var i = 0, n = arguments.length; i !== n; ++ i ) {
 37158  
 37159  				var object = arguments[ i ],
 37160  					uuid = object.uuid,
 37161  					index = indicesByUUID[ uuid ],
 37162  					knownObject = undefined;
 37163  
 37164  				if ( index === undefined ) {
 37165  
 37166  					// unknown object -> add it to the ACTIVE region
 37167  
 37168  					index = nObjects ++;
 37169  					indicesByUUID[ uuid ] = index;
 37170  					objects.push( object );
 37171  
 37172  					// accounting is done, now do the same for all bindings
 37173  
 37174  					for ( var j = 0, m = nBindings; j !== m; ++ j ) {
 37175  
 37176  						bindings[ j ].push(
 37177  								new PropertyBinding(
 37178  									object, paths[ j ], parsedPaths[ j ] ) );
 37179  
 37180  					}
 37181  
 37182  				} else if ( index < nCachedObjects ) {
 37183  
 37184  					knownObject = objects[ index ];
 37185  
 37186  					// move existing object to the ACTIVE region
 37187  
 37188  					var firstActiveIndex = -- nCachedObjects,
 37189  						lastCachedObject = objects[ firstActiveIndex ];
 37190  
 37191  					indicesByUUID[ lastCachedObject.uuid ] = index;
 37192  					objects[ index ] = lastCachedObject;
 37193  
 37194  					indicesByUUID[ uuid ] = firstActiveIndex;
 37195  					objects[ firstActiveIndex ] = object;
 37196  
 37197  					// accounting is done, now do the same for all bindings
 37198  
 37199  					for ( var j = 0, m = nBindings; j !== m; ++ j ) {
 37200  
 37201  						var bindingsForPath = bindings[ j ],
 37202  							lastCached = bindingsForPath[ firstActiveIndex ],
 37203  							binding = bindingsForPath[ index ];
 37204  
 37205  						bindingsForPath[ index ] = lastCached;
 37206  
 37207  						if ( binding === undefined ) {
 37208  
 37209  							// since we do not bother to create new bindings
 37210  							// for objects that are cached, the binding may
 37211  							// or may not exist
 37212  
 37213  							binding = new PropertyBinding(
 37214  									object, paths[ j ], parsedPaths[ j ] );
 37215  
 37216  						}
 37217  
 37218  						bindingsForPath[ firstActiveIndex ] = binding;
 37219  
 37220  					}
 37221  
 37222  				} else if ( objects[ index ] !== knownObject) {
 37223  
 37224  					console.error( "Different objects with the same UUID " +
 37225  							"detected. Clean the caches or recreate your " +
 37226  							"infrastructure when reloading scenes..." );
 37227  
 37228  				} // else the object is already where we want it to be
 37229  
 37230  			} // for arguments
 37231  
 37232  			this.nCachedObjects_ = nCachedObjects;
 37233  
 37234  		},
 37235  
 37236  		remove: function( var_args ) {
 37237  
 37238  			var objects = this._objects,
 37239  				nCachedObjects = this.nCachedObjects_,
 37240  				indicesByUUID = this._indicesByUUID,
 37241  				bindings = this._bindings,
 37242  				nBindings = bindings.length;
 37243  
 37244  			for ( var i = 0, n = arguments.length; i !== n; ++ i ) {
 37245  
 37246  				var object = arguments[ i ],
 37247  					uuid = object.uuid,
 37248  					index = indicesByUUID[ uuid ];
 37249  
 37250  				if ( index !== undefined && index >= nCachedObjects ) {
 37251  
 37252  					// move existing object into the CACHED region
 37253  
 37254  					var lastCachedIndex = nCachedObjects ++,
 37255  						firstActiveObject = objects[ lastCachedIndex ];
 37256  
 37257  					indicesByUUID[ firstActiveObject.uuid ] = index;
 37258  					objects[ index ] = firstActiveObject;
 37259  
 37260  					indicesByUUID[ uuid ] = lastCachedIndex;
 37261  					objects[ lastCachedIndex ] = object;
 37262  
 37263  					// accounting is done, now do the same for all bindings
 37264  
 37265  					for ( var j = 0, m = nBindings; j !== m; ++ j ) {
 37266  
 37267  						var bindingsForPath = bindings[ j ],
 37268  							firstActive = bindingsForPath[ lastCachedIndex ],
 37269  							binding = bindingsForPath[ index ];
 37270  
 37271  						bindingsForPath[ index ] = firstActive;
 37272  						bindingsForPath[ lastCachedIndex ] = binding;
 37273  
 37274  					}
 37275  
 37276  				}
 37277  
 37278  			} // for arguments
 37279  
 37280  			this.nCachedObjects_ = nCachedObjects;
 37281  
 37282  		},
 37283  
 37284  		// remove & forget
 37285  		uncache: function( var_args ) {
 37286  
 37287  			var objects = this._objects,
 37288  				nObjects = objects.length,
 37289  				nCachedObjects = this.nCachedObjects_,
 37290  				indicesByUUID = this._indicesByUUID,
 37291  				bindings = this._bindings,
 37292  				nBindings = bindings.length;
 37293  
 37294  			for ( var i = 0, n = arguments.length; i !== n; ++ i ) {
 37295  
 37296  				var object = arguments[ i ],
 37297  					uuid = object.uuid,
 37298  					index = indicesByUUID[ uuid ];
 37299  
 37300  				if ( index !== undefined ) {
 37301  
 37302  					delete indicesByUUID[ uuid ];
 37303  
 37304  					if ( index < nCachedObjects ) {
 37305  
 37306  						// object is cached, shrink the CACHED region
 37307  
 37308  						var firstActiveIndex = -- nCachedObjects,
 37309  							lastCachedObject = objects[ firstActiveIndex ],
 37310  							lastIndex = -- nObjects,
 37311  							lastObject = objects[ lastIndex ];
 37312  
 37313  						// last cached object takes this object's place
 37314  						indicesByUUID[ lastCachedObject.uuid ] = index;
 37315  						objects[ index ] = lastCachedObject;
 37316  
 37317  						// last object goes to the activated slot and pop
 37318  						indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
 37319  						objects[ firstActiveIndex ] = lastObject;
 37320  						objects.pop();
 37321  
 37322  						// accounting is done, now do the same for all bindings
 37323  
 37324  						for ( var j = 0, m = nBindings; j !== m; ++ j ) {
 37325  
 37326  							var bindingsForPath = bindings[ j ],
 37327  								lastCached = bindingsForPath[ firstActiveIndex ],
 37328  								last = bindingsForPath[ lastIndex ];
 37329  
 37330  							bindingsForPath[ index ] = lastCached;
 37331  							bindingsForPath[ firstActiveIndex ] = last;
 37332  							bindingsForPath.pop();
 37333  
 37334  						}
 37335  
 37336  					} else {
 37337  
 37338  						// object is active, just swap with the last and pop
 37339  
 37340  						var lastIndex = -- nObjects,
 37341  							lastObject = objects[ lastIndex ];
 37342  
 37343  						indicesByUUID[ lastObject.uuid ] = index;
 37344  						objects[ index ] = lastObject;
 37345  						objects.pop();
 37346  
 37347  						// accounting is done, now do the same for all bindings
 37348  
 37349  						for ( var j = 0, m = nBindings; j !== m; ++ j ) {
 37350  
 37351  							var bindingsForPath = bindings[ j ];
 37352  
 37353  							bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
 37354  							bindingsForPath.pop();
 37355  
 37356  						}
 37357  
 37358  					} // cached or active
 37359  
 37360  				} // if object is known
 37361  
 37362  			} // for arguments
 37363  
 37364  			this.nCachedObjects_ = nCachedObjects;
 37365  
 37366  		},
 37367  
 37368  		// Internal interface used by befriended PropertyBinding.Composite:
 37369  
 37370  		subscribe_: function( path, parsedPath ) {
 37371  			// returns an array of bindings for the given path that is changed
 37372  			// according to the contained objects in the group
 37373  
 37374  			var indicesByPath = this._bindingsIndicesByPath,
 37375  				index = indicesByPath[ path ],
 37376  				bindings = this._bindings;
 37377  
 37378  			if ( index !== undefined ) return bindings[ index ];
 37379  
 37380  			var paths = this._paths,
 37381  				parsedPaths = this._parsedPaths,
 37382  				objects = this._objects,
 37383  				nObjects = objects.length,
 37384  				nCachedObjects = this.nCachedObjects_,
 37385  				bindingsForPath = new Array( nObjects );
 37386  
 37387  			index = bindings.length;
 37388  
 37389  			indicesByPath[ path ] = index;
 37390  
 37391  			paths.push( path );
 37392  			parsedPaths.push( parsedPath );
 37393  			bindings.push( bindingsForPath );
 37394  
 37395  			for ( var i = nCachedObjects,
 37396  					n = objects.length; i !== n; ++ i ) {
 37397  
 37398  				var object = objects[ i ];
 37399  
 37400  				bindingsForPath[ i ] =
 37401  						new PropertyBinding( object, path, parsedPath );
 37402  
 37403  			}
 37404  
 37405  			return bindingsForPath;
 37406  
 37407  		},
 37408  
 37409  		unsubscribe_: function( path ) {
 37410  			// tells the group to forget about a property path and no longer
 37411  			// update the array previously obtained with 'subscribe_'
 37412  
 37413  			var indicesByPath = this._bindingsIndicesByPath,
 37414  				index = indicesByPath[ path ];
 37415  
 37416  			if ( index !== undefined ) {
 37417  
 37418  				var paths = this._paths,
 37419  					parsedPaths = this._parsedPaths,
 37420  					bindings = this._bindings,
 37421  					lastBindingsIndex = bindings.length - 1,
 37422  					lastBindings = bindings[ lastBindingsIndex ],
 37423  					lastBindingsPath = path[ lastBindingsIndex ];
 37424  
 37425  				indicesByPath[ lastBindingsPath ] = index;
 37426  
 37427  				bindings[ index ] = lastBindings;
 37428  				bindings.pop();
 37429  
 37430  				parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
 37431  				parsedPaths.pop();
 37432  
 37433  				paths[ index ] = paths[ lastBindingsIndex ];
 37434  				paths.pop();
 37435  
 37436  			}
 37437  
 37438  		}
 37439  
 37440  	};
 37441  
 37442  	/**
 37443  	 *
 37444  	 * Action provided by AnimationMixer for scheduling clip playback on specific
 37445  	 * objects.
 37446  	 *
 37447  	 * @author Ben Houston / http://clara.io/
 37448  	 * @author David Sarno / http://lighthaus.us/
 37449  	 * @author tschw
 37450  	 *
 37451  	 */
 37452  
 37453  	function AnimationAction( mixer, clip, localRoot ) {
 37454  
 37455  		this._mixer = mixer;
 37456  		this._clip = clip;
 37457  		this._localRoot = localRoot || null;
 37458  
 37459  		var tracks = clip.tracks,
 37460  			nTracks = tracks.length,
 37461  			interpolants = new Array( nTracks );
 37462  
 37463  		var interpolantSettings = {
 37464  				endingStart: 	ZeroCurvatureEnding,
 37465  				endingEnd:		ZeroCurvatureEnding
 37466  		};
 37467  
 37468  		for ( var i = 0; i !== nTracks; ++ i ) {
 37469  
 37470  			var interpolant = tracks[ i ].createInterpolant( null );
 37471  			interpolants[ i ] = interpolant;
 37472  			interpolant.settings = interpolantSettings;
 37473  
 37474  		}
 37475  
 37476  		this._interpolantSettings = interpolantSettings;
 37477  
 37478  		this._interpolants = interpolants;	// bound by the mixer
 37479  
 37480  		// inside: PropertyMixer (managed by the mixer)
 37481  		this._propertyBindings = new Array( nTracks );
 37482  
 37483  		this._cacheIndex = null;			// for the memory manager
 37484  		this._byClipCacheIndex = null;		// for the memory manager
 37485  
 37486  		this._timeScaleInterpolant = null;
 37487  		this._weightInterpolant = null;
 37488  
 37489  		this.loop = LoopRepeat;
 37490  		this._loopCount = -1;
 37491  
 37492  		// global mixer time when the action is to be started
 37493  		// it's set back to 'null' upon start of the action
 37494  		this._startTime = null;
 37495  
 37496  		// scaled local time of the action
 37497  		// gets clamped or wrapped to 0..clip.duration according to loop
 37498  		this.time = 0;
 37499  
 37500  		this.timeScale = 1;
 37501  		this._effectiveTimeScale = 1;
 37502  
 37503  		this.weight = 1;
 37504  		this._effectiveWeight = 1;
 37505  
 37506  		this.repetitions = Infinity; 		// no. of repetitions when looping
 37507  
 37508  		this.paused = false;				// false -> zero effective time scale
 37509  		this.enabled = true;				// true -> zero effective weight
 37510  
 37511  		this.clampWhenFinished 	= false;	// keep feeding the last frame?
 37512  
 37513  		this.zeroSlopeAtStart 	= true;		// for smooth interpolation w/o separate
 37514  		this.zeroSlopeAtEnd		= true;		// clips for start, loop and end
 37515  
 37516  	}
 37517  
 37518  	AnimationAction.prototype = {
 37519  
 37520  		constructor: AnimationAction,
 37521  
 37522  		// State & Scheduling
 37523  
 37524  		play: function() {
 37525  
 37526  			this._mixer._activateAction( this );
 37527  
 37528  			return this;
 37529  
 37530  		},
 37531  
 37532  		stop: function() {
 37533  
 37534  			this._mixer._deactivateAction( this );
 37535  
 37536  			return this.reset();
 37537  
 37538  		},
 37539  
 37540  		reset: function() {
 37541  
 37542  			this.paused = false;
 37543  			this.enabled = true;
 37544  
 37545  			this.time = 0;			// restart clip
 37546  			this._loopCount = -1;	// forget previous loops
 37547  			this._startTime = null;	// forget scheduling
 37548  
 37549  			return this.stopFading().stopWarping();
 37550  
 37551  		},
 37552  
 37553  		isRunning: function() {
 37554  
 37555  			return this.enabled && ! this.paused && this.timeScale !== 0 &&
 37556  					this._startTime === null && this._mixer._isActiveAction( this );
 37557  
 37558  		},
 37559  
 37560  		// return true when play has been called
 37561  		isScheduled: function() {
 37562  
 37563  			return this._mixer._isActiveAction( this );
 37564  
 37565  		},
 37566  
 37567  		startAt: function( time ) {
 37568  
 37569  			this._startTime = time;
 37570  
 37571  			return this;
 37572  
 37573  		},
 37574  
 37575  		setLoop: function( mode, repetitions ) {
 37576  
 37577  			this.loop = mode;
 37578  			this.repetitions = repetitions;
 37579  
 37580  			return this;
 37581  
 37582  		},
 37583  
 37584  		// Weight
 37585  
 37586  		// set the weight stopping any scheduled fading
 37587  		// although .enabled = false yields an effective weight of zero, this
 37588  		// method does *not* change .enabled, because it would be confusing
 37589  		setEffectiveWeight: function( weight ) {
 37590  
 37591  			this.weight = weight;
 37592  
 37593  			// note: same logic as when updated at runtime
 37594  			this._effectiveWeight = this.enabled ? weight : 0;
 37595  
 37596  			return this.stopFading();
 37597  
 37598  		},
 37599  
 37600  		// return the weight considering fading and .enabled
 37601  		getEffectiveWeight: function() {
 37602  
 37603  			return this._effectiveWeight;
 37604  
 37605  		},
 37606  
 37607  		fadeIn: function( duration ) {
 37608  
 37609  			return this._scheduleFading( duration, 0, 1 );
 37610  
 37611  		},
 37612  
 37613  		fadeOut: function( duration ) {
 37614  
 37615  			return this._scheduleFading( duration, 1, 0 );
 37616  
 37617  		},
 37618  
 37619  		crossFadeFrom: function( fadeOutAction, duration, warp ) {
 37620  
 37621  			fadeOutAction.fadeOut( duration );
 37622  			this.fadeIn( duration );
 37623  
 37624  			if( warp ) {
 37625  
 37626  				var fadeInDuration = this._clip.duration,
 37627  					fadeOutDuration = fadeOutAction._clip.duration,
 37628  
 37629  					startEndRatio = fadeOutDuration / fadeInDuration,
 37630  					endStartRatio = fadeInDuration / fadeOutDuration;
 37631  
 37632  				fadeOutAction.warp( 1.0, startEndRatio, duration );
 37633  				this.warp( endStartRatio, 1.0, duration );
 37634  
 37635  			}
 37636  
 37637  			return this;
 37638  
 37639  		},
 37640  
 37641  		crossFadeTo: function( fadeInAction, duration, warp ) {
 37642  
 37643  			return fadeInAction.crossFadeFrom( this, duration, warp );
 37644  
 37645  		},
 37646  
 37647  		stopFading: function() {
 37648  
 37649  			var weightInterpolant = this._weightInterpolant;
 37650  
 37651  			if ( weightInterpolant !== null ) {
 37652  
 37653  				this._weightInterpolant = null;
 37654  				this._mixer._takeBackControlInterpolant( weightInterpolant );
 37655  
 37656  			}
 37657  
 37658  			return this;
 37659  
 37660  		},
 37661  
 37662  		// Time Scale Control
 37663  
 37664  		// set the weight stopping any scheduled warping
 37665  		// although .paused = true yields an effective time scale of zero, this
 37666  		// method does *not* change .paused, because it would be confusing
 37667  		setEffectiveTimeScale: function( timeScale ) {
 37668  
 37669  			this.timeScale = timeScale;
 37670  			this._effectiveTimeScale = this.paused ? 0 :timeScale;
 37671  
 37672  			return this.stopWarping();
 37673  
 37674  		},
 37675  
 37676  		// return the time scale considering warping and .paused
 37677  		getEffectiveTimeScale: function() {
 37678  
 37679  			return this._effectiveTimeScale;
 37680  
 37681  		},
 37682  
 37683  		setDuration: function( duration ) {
 37684  
 37685  			this.timeScale = this._clip.duration / duration;
 37686  
 37687  			return this.stopWarping();
 37688  
 37689  		},
 37690  
 37691  		syncWith: function( action ) {
 37692  
 37693  			this.time = action.time;
 37694  			this.timeScale = action.timeScale;
 37695  
 37696  			return this.stopWarping();
 37697  
 37698  		},
 37699  
 37700  		halt: function( duration ) {
 37701  
 37702  			return this.warp( this._effectiveTimeScale, 0, duration );
 37703  
 37704  		},
 37705  
 37706  		warp: function( startTimeScale, endTimeScale, duration ) {
 37707  
 37708  			var mixer = this._mixer, now = mixer.time,
 37709  				interpolant = this._timeScaleInterpolant,
 37710  
 37711  				timeScale = this.timeScale;
 37712  
 37713  			if ( interpolant === null ) {
 37714  
 37715  				interpolant = mixer._lendControlInterpolant();
 37716  				this._timeScaleInterpolant = interpolant;
 37717  
 37718  			}
 37719  
 37720  			var times = interpolant.parameterPositions,
 37721  				values = interpolant.sampleValues;
 37722  
 37723  			times[ 0 ] = now;
 37724  			times[ 1 ] = now + duration;
 37725  
 37726  			values[ 0 ] = startTimeScale / timeScale;
 37727  			values[ 1 ] = endTimeScale / timeScale;
 37728  
 37729  			return this;
 37730  
 37731  		},
 37732  
 37733  		stopWarping: function() {
 37734  
 37735  			var timeScaleInterpolant = this._timeScaleInterpolant;
 37736  
 37737  			if ( timeScaleInterpolant !== null ) {
 37738  
 37739  				this._timeScaleInterpolant = null;
 37740  				this._mixer._takeBackControlInterpolant( timeScaleInterpolant );
 37741  
 37742  			}
 37743  
 37744  			return this;
 37745  
 37746  		},
 37747  
 37748  		// Object Accessors
 37749  
 37750  		getMixer: function() {
 37751  
 37752  			return this._mixer;
 37753  
 37754  		},
 37755  
 37756  		getClip: function() {
 37757  
 37758  			return this._clip;
 37759  
 37760  		},
 37761  
 37762  		getRoot: function() {
 37763  
 37764  			return this._localRoot || this._mixer._root;
 37765  
 37766  		},
 37767  
 37768  		// Interna
 37769  
 37770  		_update: function( time, deltaTime, timeDirection, accuIndex ) {
 37771  			// called by the mixer
 37772  
 37773  			var startTime = this._startTime;
 37774  
 37775  			if ( startTime !== null ) {
 37776  
 37777  				// check for scheduled start of action
 37778  
 37779  				var timeRunning = ( time - startTime ) * timeDirection;
 37780  				if ( timeRunning < 0 || timeDirection === 0 ) {
 37781  
 37782  					return; // yet to come / don't decide when delta = 0
 37783  
 37784  				}
 37785  
 37786  				// start
 37787  
 37788  				this._startTime = null; // unschedule
 37789  				deltaTime = timeDirection * timeRunning;
 37790  
 37791  			}
 37792  
 37793  			// apply time scale and advance time
 37794  
 37795  			deltaTime *= this._updateTimeScale( time );
 37796  			var clipTime = this._updateTime( deltaTime );
 37797  
 37798  			// note: _updateTime may disable the action resulting in
 37799  			// an effective weight of 0
 37800  
 37801  			var weight = this._updateWeight( time );
 37802  
 37803  			if ( weight > 0 ) {
 37804  
 37805  				var interpolants = this._interpolants;
 37806  				var propertyMixers = this._propertyBindings;
 37807  
 37808  				for ( var j = 0, m = interpolants.length; j !== m; ++ j ) {
 37809  
 37810  					interpolants[ j ].evaluate( clipTime );
 37811  					propertyMixers[ j ].accumulate( accuIndex, weight );
 37812  
 37813  				}
 37814  
 37815  			}
 37816  
 37817  		},
 37818  
 37819  		_updateWeight: function( time ) {
 37820  
 37821  			var weight = 0;
 37822  
 37823  			if ( this.enabled ) {
 37824  
 37825  				weight = this.weight;
 37826  				var interpolant = this._weightInterpolant;
 37827  
 37828  				if ( interpolant !== null ) {
 37829  
 37830  					var interpolantValue = interpolant.evaluate( time )[ 0 ];
 37831  
 37832  					weight *= interpolantValue;
 37833  
 37834  					if ( time > interpolant.parameterPositions[ 1 ] ) {
 37835  
 37836  						this.stopFading();
 37837  
 37838  						if ( interpolantValue === 0 ) {
 37839  
 37840  							// faded out, disable
 37841  							this.enabled = false;
 37842  
 37843  						}
 37844  
 37845  					}
 37846  
 37847  				}
 37848  
 37849  			}
 37850  
 37851  			this._effectiveWeight = weight;
 37852  			return weight;
 37853  
 37854  		},
 37855  
 37856  		_updateTimeScale: function( time ) {
 37857  
 37858  			var timeScale = 0;
 37859  
 37860  			if ( ! this.paused ) {
 37861  
 37862  				timeScale = this.timeScale;
 37863  
 37864  				var interpolant = this._timeScaleInterpolant;
 37865  
 37866  				if ( interpolant !== null ) {
 37867  
 37868  					var interpolantValue = interpolant.evaluate( time )[ 0 ];
 37869  
 37870  					timeScale *= interpolantValue;
 37871  
 37872  					if ( time > interpolant.parameterPositions[ 1 ] ) {
 37873  
 37874  						this.stopWarping();
 37875  
 37876  						if ( timeScale === 0 ) {
 37877  
 37878  							// motion has halted, pause
 37879  							this.paused = true;
 37880  
 37881  						} else {
 37882  
 37883  							// warp done - apply final time scale
 37884  							this.timeScale = timeScale;
 37885  
 37886  						}
 37887  
 37888  					}
 37889  
 37890  				}
 37891  
 37892  			}
 37893  
 37894  			this._effectiveTimeScale = timeScale;
 37895  			return timeScale;
 37896  
 37897  		},
 37898  
 37899  		_updateTime: function( deltaTime ) {
 37900  
 37901  			var time = this.time + deltaTime;
 37902  
 37903  			if ( deltaTime === 0 ) return time;
 37904  
 37905  			var duration = this._clip.duration,
 37906  
 37907  				loop = this.loop,
 37908  				loopCount = this._loopCount;
 37909  
 37910  			if ( loop === LoopOnce ) {
 37911  
 37912  				if ( loopCount === -1 ) {
 37913  					// just started
 37914  
 37915  					this._loopCount = 0;
 37916  					this._setEndings( true, true, false );
 37917  
 37918  				}
 37919  
 37920  				handle_stop: {
 37921  
 37922  					if ( time >= duration ) {
 37923  
 37924  						time = duration;
 37925  
 37926  					} else if ( time < 0 ) {
 37927  
 37928  						time = 0;
 37929  
 37930  					} else break handle_stop;
 37931  
 37932  					if ( this.clampWhenFinished ) this.paused = true;
 37933  					else this.enabled = false;
 37934  
 37935  					this._mixer.dispatchEvent( {
 37936  						type: 'finished', action: this,
 37937  						direction: deltaTime < 0 ? -1 : 1
 37938  					} );
 37939  
 37940  				}
 37941  
 37942  			} else { // repetitive Repeat or PingPong
 37943  
 37944  				var pingPong = ( loop === LoopPingPong );
 37945  
 37946  				if ( loopCount === -1 ) {
 37947  					// just started
 37948  
 37949  					if ( deltaTime >= 0 ) {
 37950  
 37951  						loopCount = 0;
 37952  
 37953  						this._setEndings(
 37954  								true, this.repetitions === 0, pingPong );
 37955  
 37956  					} else {
 37957  
 37958  						// when looping in reverse direction, the initial
 37959  						// transition through zero counts as a repetition,
 37960  						// so leave loopCount at -1
 37961  
 37962  						this._setEndings(
 37963  								this.repetitions === 0, true, pingPong );
 37964  
 37965  					}
 37966  
 37967  				}
 37968  
 37969  				if ( time >= duration || time < 0 ) {
 37970  					// wrap around
 37971  
 37972  					var loopDelta = Math.floor( time / duration ); // signed
 37973  					time -= duration * loopDelta;
 37974  
 37975  					loopCount += Math.abs( loopDelta );
 37976  
 37977  					var pending = this.repetitions - loopCount;
 37978  
 37979  					if ( pending < 0 ) {
 37980  						// have to stop (switch state, clamp time, fire event)
 37981  
 37982  						if ( this.clampWhenFinished ) this.paused = true;
 37983  						else this.enabled = false;
 37984  
 37985  						time = deltaTime > 0 ? duration : 0;
 37986  
 37987  						this._mixer.dispatchEvent( {
 37988  							type: 'finished', action: this,
 37989  							direction: deltaTime > 0 ? 1 : -1
 37990  						} );
 37991  
 37992  					} else {
 37993  						// keep running
 37994  
 37995  						if ( pending === 0 ) {
 37996  							// entering the last round
 37997  
 37998  							var atStart = deltaTime < 0;
 37999  							this._setEndings( atStart, ! atStart, pingPong );
 38000  
 38001  						} else {
 38002  
 38003  							this._setEndings( false, false, pingPong );
 38004  
 38005  						}
 38006  
 38007  						this._loopCount = loopCount;
 38008  
 38009  						this._mixer.dispatchEvent( {
 38010  							type: 'loop', action: this, loopDelta: loopDelta
 38011  						} );
 38012  
 38013  					}
 38014  
 38015  				}
 38016  
 38017  				if ( pingPong && ( loopCount & 1 ) === 1 ) {
 38018  					// invert time for the "pong round"
 38019  
 38020  					this.time = time;
 38021  					return duration - time;
 38022  
 38023  				}
 38024  
 38025  			}
 38026  
 38027  			this.time = time;
 38028  			return time;
 38029  
 38030  		},
 38031  
 38032  		_setEndings: function( atStart, atEnd, pingPong ) {
 38033  
 38034  			var settings = this._interpolantSettings;
 38035  
 38036  			if ( pingPong ) {
 38037  
 38038  				settings.endingStart 	= ZeroSlopeEnding;
 38039  				settings.endingEnd		= ZeroSlopeEnding;
 38040  
 38041  			} else {
 38042  
 38043  				// assuming for LoopOnce atStart == atEnd == true
 38044  
 38045  				if ( atStart ) {
 38046  
 38047  					settings.endingStart = this.zeroSlopeAtStart ?
 38048  							ZeroSlopeEnding : ZeroCurvatureEnding;
 38049  
 38050  				} else {
 38051  
 38052  					settings.endingStart = WrapAroundEnding;
 38053  
 38054  				}
 38055  
 38056  				if ( atEnd ) {
 38057  
 38058  					settings.endingEnd = this.zeroSlopeAtEnd ?
 38059  							ZeroSlopeEnding : ZeroCurvatureEnding;
 38060  
 38061  				} else {
 38062  
 38063  					settings.endingEnd 	 = WrapAroundEnding;
 38064  
 38065  				}
 38066  
 38067  			}
 38068  
 38069  		},
 38070  
 38071  		_scheduleFading: function( duration, weightNow, weightThen ) {
 38072  
 38073  			var mixer = this._mixer, now = mixer.time,
 38074  				interpolant = this._weightInterpolant;
 38075  
 38076  			if ( interpolant === null ) {
 38077  
 38078  				interpolant = mixer._lendControlInterpolant();
 38079  				this._weightInterpolant = interpolant;
 38080  
 38081  			}
 38082  
 38083  			var times = interpolant.parameterPositions,
 38084  				values = interpolant.sampleValues;
 38085  
 38086  			times[ 0 ] = now; 				values[ 0 ] = weightNow;
 38087  			times[ 1 ] = now + duration;	values[ 1 ] = weightThen;
 38088  
 38089  			return this;
 38090  
 38091  		}
 38092  
 38093  	};
 38094  
 38095  	/**
 38096  	 *
 38097  	 * Player for AnimationClips.
 38098  	 *
 38099  	 *
 38100  	 * @author Ben Houston / http://clara.io/
 38101  	 * @author David Sarno / http://lighthaus.us/
 38102  	 * @author tschw
 38103  	 */
 38104  
 38105  	function AnimationMixer( root ) {
 38106  
 38107  		this._root = root;
 38108  		this._initMemoryManager();
 38109  		this._accuIndex = 0;
 38110  
 38111  		this.time = 0;
 38112  
 38113  		this.timeScale = 1.0;
 38114  
 38115  	}
 38116  
 38117  	AnimationMixer.prototype = {
 38118  
 38119  		constructor: AnimationMixer,
 38120  
 38121  		// return an action for a clip optionally using a custom root target
 38122  		// object (this method allocates a lot of dynamic memory in case a
 38123  		// previously unknown clip/root combination is specified)
 38124  		clipAction: function ( clip, optionalRoot ) {
 38125  
 38126  			var root = optionalRoot || this._root,
 38127  				rootUuid = root.uuid,
 38128  
 38129  				clipObject = typeof clip === 'string' ?
 38130  						AnimationClip.findByName( root, clip ) : clip,
 38131  
 38132  				clipUuid = clipObject !== null ? clipObject.uuid : clip,
 38133  
 38134  				actionsForClip = this._actionsByClip[ clipUuid ],
 38135  				prototypeAction = null;
 38136  
 38137  			if ( actionsForClip !== undefined ) {
 38138  
 38139  				var existingAction =
 38140  						actionsForClip.actionByRoot[ rootUuid ];
 38141  
 38142  				if ( existingAction !== undefined ) {
 38143  
 38144  					return existingAction;
 38145  
 38146  				}
 38147  
 38148  				// we know the clip, so we don't have to parse all
 38149  				// the bindings again but can just copy
 38150  				prototypeAction = actionsForClip.knownActions[ 0 ];
 38151  
 38152  				// also, take the clip from the prototype action
 38153  				if ( clipObject === null )
 38154  					clipObject = prototypeAction._clip;
 38155  
 38156  			}
 38157  
 38158  			// clip must be known when specified via string
 38159  			if ( clipObject === null ) return null;
 38160  
 38161  			// allocate all resources required to run it
 38162  			var newAction = new AnimationAction( this, clipObject, optionalRoot );
 38163  
 38164  			this._bindAction( newAction, prototypeAction );
 38165  
 38166  			// and make the action known to the memory manager
 38167  			this._addInactiveAction( newAction, clipUuid, rootUuid );
 38168  
 38169  			return newAction;
 38170  
 38171  		},
 38172  
 38173  		// get an existing action
 38174  		existingAction: function ( clip, optionalRoot ) {
 38175  
 38176  			var root = optionalRoot || this._root,
 38177  				rootUuid = root.uuid,
 38178  
 38179  				clipObject = typeof clip === 'string' ?
 38180  						AnimationClip.findByName( root, clip ) : clip,
 38181  
 38182  				clipUuid = clipObject ? clipObject.uuid : clip,
 38183  
 38184  				actionsForClip = this._actionsByClip[ clipUuid ];
 38185  
 38186  			if ( actionsForClip !== undefined ) {
 38187  
 38188  				return actionsForClip.actionByRoot[ rootUuid ] || null;
 38189  
 38190  			}
 38191  
 38192  			return null;
 38193  
 38194  		},
 38195  
 38196  		// deactivates all previously scheduled actions
 38197  		stopAllAction: function () {
 38198  
 38199  			var actions = this._actions,
 38200  				nActions = this._nActiveActions,
 38201  				bindings = this._bindings,
 38202  				nBindings = this._nActiveBindings;
 38203  
 38204  			this._nActiveActions = 0;
 38205  			this._nActiveBindings = 0;
 38206  
 38207  			for ( var i = 0; i !== nActions; ++ i ) {
 38208  
 38209  				actions[ i ].reset();
 38210  
 38211  			}
 38212  
 38213  			for ( var i = 0; i !== nBindings; ++ i ) {
 38214  
 38215  				bindings[ i ].useCount = 0;
 38216  
 38217  			}
 38218  
 38219  			return this;
 38220  
 38221  		},
 38222  
 38223  		// advance the time and update apply the animation
 38224  		update: function ( deltaTime ) {
 38225  
 38226  			deltaTime *= this.timeScale;
 38227  
 38228  			var actions = this._actions,
 38229  				nActions = this._nActiveActions,
 38230  
 38231  				time = this.time += deltaTime,
 38232  				timeDirection = Math.sign( deltaTime ),
 38233  
 38234  				accuIndex = this._accuIndex ^= 1;
 38235  
 38236  			// run active actions
 38237  
 38238  			for ( var i = 0; i !== nActions; ++ i ) {
 38239  
 38240  				var action = actions[ i ];
 38241  
 38242  				if ( action.enabled ) {
 38243  
 38244  					action._update( time, deltaTime, timeDirection, accuIndex );
 38245  
 38246  				}
 38247  
 38248  			}
 38249  
 38250  			// update scene graph
 38251  
 38252  			var bindings = this._bindings,
 38253  				nBindings = this._nActiveBindings;
 38254  
 38255  			for ( var i = 0; i !== nBindings; ++ i ) {
 38256  
 38257  				bindings[ i ].apply( accuIndex );
 38258  
 38259  			}
 38260  
 38261  			return this;
 38262  
 38263  		},
 38264  
 38265  		// return this mixer's root target object
 38266  		getRoot: function () {
 38267  
 38268  			return this._root;
 38269  
 38270  		},
 38271  
 38272  		// free all resources specific to a particular clip
 38273  		uncacheClip: function ( clip ) {
 38274  
 38275  			var actions = this._actions,
 38276  				clipUuid = clip.uuid,
 38277  				actionsByClip = this._actionsByClip,
 38278  				actionsForClip = actionsByClip[ clipUuid ];
 38279  
 38280  			if ( actionsForClip !== undefined ) {
 38281  
 38282  				// note: just calling _removeInactiveAction would mess up the
 38283  				// iteration state and also require updating the state we can
 38284  				// just throw away
 38285  
 38286  				var actionsToRemove = actionsForClip.knownActions;
 38287  
 38288  				for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) {
 38289  
 38290  					var action = actionsToRemove[ i ];
 38291  
 38292  					this._deactivateAction( action );
 38293  
 38294  					var cacheIndex = action._cacheIndex,
 38295  						lastInactiveAction = actions[ actions.length - 1 ];
 38296  
 38297  					action._cacheIndex = null;
 38298  					action._byClipCacheIndex = null;
 38299  
 38300  					lastInactiveAction._cacheIndex = cacheIndex;
 38301  					actions[ cacheIndex ] = lastInactiveAction;
 38302  					actions.pop();
 38303  
 38304  					this._removeInactiveBindingsForAction( action );
 38305  
 38306  				}
 38307  
 38308  				delete actionsByClip[ clipUuid ];
 38309  
 38310  			}
 38311  
 38312  		},
 38313  
 38314  		// free all resources specific to a particular root target object
 38315  		uncacheRoot: function ( root ) {
 38316  
 38317  			var rootUuid = root.uuid,
 38318  				actionsByClip = this._actionsByClip;
 38319  
 38320  			for ( var clipUuid in actionsByClip ) {
 38321  
 38322  				var actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
 38323  					action = actionByRoot[ rootUuid ];
 38324  
 38325  				if ( action !== undefined ) {
 38326  
 38327  					this._deactivateAction( action );
 38328  					this._removeInactiveAction( action );
 38329  
 38330  				}
 38331  
 38332  			}
 38333  
 38334  			var bindingsByRoot = this._bindingsByRootAndName,
 38335  				bindingByName = bindingsByRoot[ rootUuid ];
 38336  
 38337  			if ( bindingByName !== undefined ) {
 38338  
 38339  				for ( var trackName in bindingByName ) {
 38340  
 38341  					var binding = bindingByName[ trackName ];
 38342  					binding.restoreOriginalState();
 38343  					this._removeInactiveBinding( binding );
 38344  
 38345  				}
 38346  
 38347  			}
 38348  
 38349  		},
 38350  
 38351  		// remove a targeted clip from the cache
 38352  		uncacheAction: function ( clip, optionalRoot ) {
 38353  
 38354  			var action = this.existingAction( clip, optionalRoot );
 38355  
 38356  			if ( action !== null ) {
 38357  
 38358  				this._deactivateAction( action );
 38359  				this._removeInactiveAction( action );
 38360  
 38361  			}
 38362  
 38363  		}
 38364  
 38365  	};
 38366  
 38367  	// Implementation details:
 38368  
 38369  	Object.assign( AnimationMixer.prototype, {
 38370  
 38371  		_bindAction: function ( action, prototypeAction ) {
 38372  
 38373  			var root = action._localRoot || this._root,
 38374  				tracks = action._clip.tracks,
 38375  				nTracks = tracks.length,
 38376  				bindings = action._propertyBindings,
 38377  				interpolants = action._interpolants,
 38378  				rootUuid = root.uuid,
 38379  				bindingsByRoot = this._bindingsByRootAndName,
 38380  				bindingsByName = bindingsByRoot[ rootUuid ];
 38381  
 38382  			if ( bindingsByName === undefined ) {
 38383  
 38384  				bindingsByName = {};
 38385  				bindingsByRoot[ rootUuid ] = bindingsByName;
 38386  
 38387  			}
 38388  
 38389  			for ( var i = 0; i !== nTracks; ++ i ) {
 38390  
 38391  				var track = tracks[ i ],
 38392  					trackName = track.name,
 38393  					binding = bindingsByName[ trackName ];
 38394  
 38395  				if ( binding !== undefined ) {
 38396  
 38397  					bindings[ i ] = binding;
 38398  
 38399  				} else {
 38400  
 38401  					binding = bindings[ i ];
 38402  
 38403  					if ( binding !== undefined ) {
 38404  
 38405  						// existing binding, make sure the cache knows
 38406  
 38407  						if ( binding._cacheIndex === null ) {
 38408  
 38409  							++ binding.referenceCount;
 38410  							this._addInactiveBinding( binding, rootUuid, trackName );
 38411  
 38412  						}
 38413  
 38414  						continue;
 38415  
 38416  					}
 38417  
 38418  					var path = prototypeAction && prototypeAction.
 38419  							_propertyBindings[ i ].binding.parsedPath;
 38420  
 38421  					binding = new PropertyMixer(
 38422  							PropertyBinding.create( root, trackName, path ),
 38423  							track.ValueTypeName, track.getValueSize() );
 38424  
 38425  					++ binding.referenceCount;
 38426  					this._addInactiveBinding( binding, rootUuid, trackName );
 38427  
 38428  					bindings[ i ] = binding;
 38429  
 38430  				}
 38431  
 38432  				interpolants[ i ].resultBuffer = binding.buffer;
 38433  
 38434  			}
 38435  
 38436  		},
 38437  
 38438  		_activateAction: function ( action ) {
 38439  
 38440  			if ( ! this._isActiveAction( action ) ) {
 38441  
 38442  				if ( action._cacheIndex === null ) {
 38443  
 38444  					// this action has been forgotten by the cache, but the user
 38445  					// appears to be still using it -> rebind
 38446  
 38447  					var rootUuid = ( action._localRoot || this._root ).uuid,
 38448  						clipUuid = action._clip.uuid,
 38449  						actionsForClip = this._actionsByClip[ clipUuid ];
 38450  
 38451  					this._bindAction( action,
 38452  							actionsForClip && actionsForClip.knownActions[ 0 ] );
 38453  
 38454  					this._addInactiveAction( action, clipUuid, rootUuid );
 38455  
 38456  				}
 38457  
 38458  				var bindings = action._propertyBindings;
 38459  
 38460  				// increment reference counts / sort out state
 38461  				for ( var i = 0, n = bindings.length; i !== n; ++ i ) {
 38462  
 38463  					var binding = bindings[ i ];
 38464  
 38465  					if ( binding.useCount ++ === 0 ) {
 38466  
 38467  						this._lendBinding( binding );
 38468  						binding.saveOriginalState();
 38469  
 38470  					}
 38471  
 38472  				}
 38473  
 38474  				this._lendAction( action );
 38475  
 38476  			}
 38477  
 38478  		},
 38479  
 38480  		_deactivateAction: function ( action ) {
 38481  
 38482  			if ( this._isActiveAction( action ) ) {
 38483  
 38484  				var bindings = action._propertyBindings;
 38485  
 38486  				// decrement reference counts / sort out state
 38487  				for ( var i = 0, n = bindings.length; i !== n; ++ i ) {
 38488  
 38489  					var binding = bindings[ i ];
 38490  
 38491  					if ( -- binding.useCount === 0 ) {
 38492  
 38493  						binding.restoreOriginalState();
 38494  						this._takeBackBinding( binding );
 38495  
 38496  					}
 38497  
 38498  				}
 38499  
 38500  				this._takeBackAction( action );
 38501  
 38502  			}
 38503  
 38504  		},
 38505  
 38506  		// Memory manager
 38507  
 38508  		_initMemoryManager: function () {
 38509  
 38510  			this._actions = []; // 'nActiveActions' followed by inactive ones
 38511  			this._nActiveActions = 0;
 38512  
 38513  			this._actionsByClip = {};
 38514  			// inside:
 38515  			// {
 38516  			// 		knownActions: Array< AnimationAction >	- used as prototypes
 38517  			// 		actionByRoot: AnimationAction			- lookup
 38518  			// }
 38519  
 38520  
 38521  			this._bindings = []; // 'nActiveBindings' followed by inactive ones
 38522  			this._nActiveBindings = 0;
 38523  
 38524  			this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >
 38525  
 38526  
 38527  			this._controlInterpolants = []; // same game as above
 38528  			this._nActiveControlInterpolants = 0;
 38529  
 38530  			var scope = this;
 38531  
 38532  			this.stats = {
 38533  
 38534  				actions: {
 38535  					get total() { return scope._actions.length; },
 38536  					get inUse() { return scope._nActiveActions; }
 38537  				},
 38538  				bindings: {
 38539  					get total() { return scope._bindings.length; },
 38540  					get inUse() { return scope._nActiveBindings; }
 38541  				},
 38542  				controlInterpolants: {
 38543  					get total() { return scope._controlInterpolants.length; },
 38544  					get inUse() { return scope._nActiveControlInterpolants; }
 38545  				}
 38546  
 38547  			};
 38548  
 38549  		},
 38550  
 38551  		// Memory management for AnimationAction objects
 38552  
 38553  		_isActiveAction: function ( action ) {
 38554  
 38555  			var index = action._cacheIndex;
 38556  			return index !== null && index < this._nActiveActions;
 38557  
 38558  		},
 38559  
 38560  		_addInactiveAction: function ( action, clipUuid, rootUuid ) {
 38561  
 38562  			var actions = this._actions,
 38563  				actionsByClip = this._actionsByClip,
 38564  				actionsForClip = actionsByClip[ clipUuid ];
 38565  
 38566  			if ( actionsForClip === undefined ) {
 38567  
 38568  				actionsForClip = {
 38569  
 38570  					knownActions: [ action ],
 38571  					actionByRoot: {}
 38572  
 38573  				};
 38574  
 38575  				action._byClipCacheIndex = 0;
 38576  
 38577  				actionsByClip[ clipUuid ] = actionsForClip;
 38578  
 38579  			} else {
 38580  
 38581  				var knownActions = actionsForClip.knownActions;
 38582  
 38583  				action._byClipCacheIndex = knownActions.length;
 38584  				knownActions.push( action );
 38585  
 38586  			}
 38587  
 38588  			action._cacheIndex = actions.length;
 38589  			actions.push( action );
 38590  
 38591  			actionsForClip.actionByRoot[ rootUuid ] = action;
 38592  
 38593  		},
 38594  
 38595  		_removeInactiveAction: function ( action ) {
 38596  
 38597  			var actions = this._actions,
 38598  				lastInactiveAction = actions[ actions.length - 1 ],
 38599  				cacheIndex = action._cacheIndex;
 38600  
 38601  			lastInactiveAction._cacheIndex = cacheIndex;
 38602  			actions[ cacheIndex ] = lastInactiveAction;
 38603  			actions.pop();
 38604  
 38605  			action._cacheIndex = null;
 38606  
 38607  
 38608  			var clipUuid = action._clip.uuid,
 38609  				actionsByClip = this._actionsByClip,
 38610  				actionsForClip = actionsByClip[ clipUuid ],
 38611  				knownActionsForClip = actionsForClip.knownActions,
 38612  
 38613  				lastKnownAction =
 38614  					knownActionsForClip[ knownActionsForClip.length - 1 ],
 38615  
 38616  				byClipCacheIndex = action._byClipCacheIndex;
 38617  
 38618  			lastKnownAction._byClipCacheIndex = byClipCacheIndex;
 38619  			knownActionsForClip[ byClipCacheIndex ] = lastKnownAction;
 38620  			knownActionsForClip.pop();
 38621  
 38622  			action._byClipCacheIndex = null;
 38623  
 38624  
 38625  			var actionByRoot = actionsForClip.actionByRoot,
 38626  				rootUuid = ( actions._localRoot || this._root ).uuid;
 38627  
 38628  			delete actionByRoot[ rootUuid ];
 38629  
 38630  			if ( knownActionsForClip.length === 0 ) {
 38631  
 38632  				delete actionsByClip[ clipUuid ];
 38633  
 38634  			}
 38635  
 38636  			this._removeInactiveBindingsForAction( action );
 38637  
 38638  		},
 38639  
 38640  		_removeInactiveBindingsForAction: function ( action ) {
 38641  
 38642  			var bindings = action._propertyBindings;
 38643  			for ( var i = 0, n = bindings.length; i !== n; ++ i ) {
 38644  
 38645  				var binding = bindings[ i ];
 38646  
 38647  				if ( -- binding.referenceCount === 0 ) {
 38648  
 38649  					this._removeInactiveBinding( binding );
 38650  
 38651  				}
 38652  
 38653  			}
 38654  
 38655  		},
 38656  
 38657  		_lendAction: function ( action ) {
 38658  
 38659  			// [ active actions |  inactive actions  ]
 38660  			// [  active actions >| inactive actions ]
 38661  			//                 s        a
 38662  			//                  <-swap->
 38663  			//                 a        s
 38664  
 38665  			var actions = this._actions,
 38666  				prevIndex = action._cacheIndex,
 38667  
 38668  				lastActiveIndex = this._nActiveActions ++,
 38669  
 38670  				firstInactiveAction = actions[ lastActiveIndex ];
 38671  
 38672  			action._cacheIndex = lastActiveIndex;
 38673  			actions[ lastActiveIndex ] = action;
 38674  
 38675  			firstInactiveAction._cacheIndex = prevIndex;
 38676  			actions[ prevIndex ] = firstInactiveAction;
 38677  
 38678  		},
 38679  
 38680  		_takeBackAction: function ( action ) {
 38681  
 38682  			// [  active actions  | inactive actions ]
 38683  			// [ active actions |< inactive actions  ]
 38684  			//        a        s
 38685  			//         <-swap->
 38686  			//        s        a
 38687  
 38688  			var actions = this._actions,
 38689  				prevIndex = action._cacheIndex,
 38690  
 38691  				firstInactiveIndex = -- this._nActiveActions,
 38692  
 38693  				lastActiveAction = actions[ firstInactiveIndex ];
 38694  
 38695  			action._cacheIndex = firstInactiveIndex;
 38696  			actions[ firstInactiveIndex ] = action;
 38697  
 38698  			lastActiveAction._cacheIndex = prevIndex;
 38699  			actions[ prevIndex ] = lastActiveAction;
 38700  
 38701  		},
 38702  
 38703  		// Memory management for PropertyMixer objects
 38704  
 38705  		_addInactiveBinding: function ( binding, rootUuid, trackName ) {
 38706  
 38707  			var bindingsByRoot = this._bindingsByRootAndName,
 38708  				bindingByName = bindingsByRoot[ rootUuid ],
 38709  
 38710  				bindings = this._bindings;
 38711  
 38712  			if ( bindingByName === undefined ) {
 38713  
 38714  				bindingByName = {};
 38715  				bindingsByRoot[ rootUuid ] = bindingByName;
 38716  
 38717  			}
 38718  
 38719  			bindingByName[ trackName ] = binding;
 38720  
 38721  			binding._cacheIndex = bindings.length;
 38722  			bindings.push( binding );
 38723  
 38724  		},
 38725  
 38726  		_removeInactiveBinding: function ( binding ) {
 38727  
 38728  			var bindings = this._bindings,
 38729  				propBinding = binding.binding,
 38730  				rootUuid = propBinding.rootNode.uuid,
 38731  				trackName = propBinding.path,
 38732  				bindingsByRoot = this._bindingsByRootAndName,
 38733  				bindingByName = bindingsByRoot[ rootUuid ],
 38734  
 38735  				lastInactiveBinding = bindings[ bindings.length - 1 ],
 38736  				cacheIndex = binding._cacheIndex;
 38737  
 38738  			lastInactiveBinding._cacheIndex = cacheIndex;
 38739  			bindings[ cacheIndex ] = lastInactiveBinding;
 38740  			bindings.pop();
 38741  
 38742  			delete bindingByName[ trackName ];
 38743  
 38744  			remove_empty_map: {
 38745  
 38746  				for ( var _ in bindingByName ) break remove_empty_map;
 38747  
 38748  				delete bindingsByRoot[ rootUuid ];
 38749  
 38750  			}
 38751  
 38752  		},
 38753  
 38754  		_lendBinding: function ( binding ) {
 38755  
 38756  			var bindings = this._bindings,
 38757  				prevIndex = binding._cacheIndex,
 38758  
 38759  				lastActiveIndex = this._nActiveBindings ++,
 38760  
 38761  				firstInactiveBinding = bindings[ lastActiveIndex ];
 38762  
 38763  			binding._cacheIndex = lastActiveIndex;
 38764  			bindings[ lastActiveIndex ] = binding;
 38765  
 38766  			firstInactiveBinding._cacheIndex = prevIndex;
 38767  			bindings[ prevIndex ] = firstInactiveBinding;
 38768  
 38769  		},
 38770  
 38771  		_takeBackBinding: function ( binding ) {
 38772  
 38773  			var bindings = this._bindings,
 38774  				prevIndex = binding._cacheIndex,
 38775  
 38776  				firstInactiveIndex = -- this._nActiveBindings,
 38777  
 38778  				lastActiveBinding = bindings[ firstInactiveIndex ];
 38779  
 38780  			binding._cacheIndex = firstInactiveIndex;
 38781  			bindings[ firstInactiveIndex ] = binding;
 38782  
 38783  			lastActiveBinding._cacheIndex = prevIndex;
 38784  			bindings[ prevIndex ] = lastActiveBinding;
 38785  
 38786  		},
 38787  
 38788  
 38789  		// Memory management of Interpolants for weight and time scale
 38790  
 38791  		_lendControlInterpolant: function () {
 38792  
 38793  			var interpolants = this._controlInterpolants,
 38794  				lastActiveIndex = this._nActiveControlInterpolants ++,
 38795  				interpolant = interpolants[ lastActiveIndex ];
 38796  
 38797  			if ( interpolant === undefined ) {
 38798  
 38799  				interpolant = new LinearInterpolant(
 38800  						new Float32Array( 2 ), new Float32Array( 2 ),
 38801  							1, this._controlInterpolantsResultBuffer );
 38802  
 38803  				interpolant.__cacheIndex = lastActiveIndex;
 38804  				interpolants[ lastActiveIndex ] = interpolant;
 38805  
 38806  			}
 38807  
 38808  			return interpolant;
 38809  
 38810  		},
 38811  
 38812  		_takeBackControlInterpolant: function ( interpolant ) {
 38813  
 38814  			var interpolants = this._controlInterpolants,
 38815  				prevIndex = interpolant.__cacheIndex,
 38816  
 38817  				firstInactiveIndex = -- this._nActiveControlInterpolants,
 38818  
 38819  				lastActiveInterpolant = interpolants[ firstInactiveIndex ];
 38820  
 38821  			interpolant.__cacheIndex = firstInactiveIndex;
 38822  			interpolants[ firstInactiveIndex ] = interpolant;
 38823  
 38824  			lastActiveInterpolant.__cacheIndex = prevIndex;
 38825  			interpolants[ prevIndex ] = lastActiveInterpolant;
 38826  
 38827  		},
 38828  
 38829  		_controlInterpolantsResultBuffer: new Float32Array( 1 )
 38830  
 38831  	} );
 38832  
 38833  	Object.assign( AnimationMixer.prototype, EventDispatcher.prototype );
 38834  
 38835  	/**
 38836  	 * @author mrdoob / http://mrdoob.com/
 38837  	 */
 38838  
 38839  	function Uniform( value ) {
 38840  
 38841  		if ( typeof value === 'string' ) {
 38842  
 38843  			console.warn( 'THREE.Uniform: Type parameter is no longer needed.' );
 38844  			value = arguments[ 1 ];
 38845  
 38846  		}
 38847  
 38848  		this.value = value;
 38849  
 38850  	}
 38851  
 38852  	Uniform.prototype.clone = function () {
 38853  
 38854  		return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );
 38855  
 38856  	};
 38857  
 38858  	/**
 38859  	 * @author benaadams / https://twitter.com/ben_a_adams
 38860  	 */
 38861  
 38862  	function InstancedBufferGeometry() {
 38863  
 38864  		BufferGeometry.call( this );
 38865  
 38866  		this.type = 'InstancedBufferGeometry';
 38867  		this.maxInstancedCount = undefined;
 38868  
 38869  	}
 38870  
 38871  	InstancedBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
 38872  	InstancedBufferGeometry.prototype.constructor = InstancedBufferGeometry;
 38873  
 38874  	InstancedBufferGeometry.prototype.isInstancedBufferGeometry = true;
 38875  
 38876  	InstancedBufferGeometry.prototype.addGroup = function ( start, count, materialIndex ) {
 38877  
 38878  		this.groups.push( {
 38879  
 38880  			start: start,
 38881  			count: count,
 38882  			materialIndex: materialIndex
 38883  
 38884  		} );
 38885  
 38886  	};
 38887  
 38888  	InstancedBufferGeometry.prototype.copy = function ( source ) {
 38889  
 38890  		var index = source.index;
 38891  
 38892  		if ( index !== null ) {
 38893  
 38894  			this.setIndex( index.clone() );
 38895  
 38896  		}
 38897  
 38898  		var attributes = source.attributes;
 38899  
 38900  		for ( var name in attributes ) {
 38901  
 38902  			var attribute = attributes[ name ];
 38903  			this.addAttribute( name, attribute.clone() );
 38904  
 38905  		}
 38906  
 38907  		var groups = source.groups;
 38908  
 38909  		for ( var i = 0, l = groups.length; i < l; i ++ ) {
 38910  
 38911  			var group = groups[ i ];
 38912  			this.addGroup( group.start, group.count, group.materialIndex );
 38913  
 38914  		}
 38915  
 38916  		return this;
 38917  
 38918  	};
 38919  
 38920  	/**
 38921  	 * @author benaadams / https://twitter.com/ben_a_adams
 38922  	 */
 38923  
 38924  	function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) {
 38925  
 38926  		this.uuid = _Math.generateUUID();
 38927  
 38928  		this.data = interleavedBuffer;
 38929  		this.itemSize = itemSize;
 38930  		this.offset = offset;
 38931  
 38932  		this.normalized = normalized === true;
 38933  
 38934  	}
 38935  
 38936  
 38937  	InterleavedBufferAttribute.prototype = {
 38938  
 38939  		constructor: InterleavedBufferAttribute,
 38940  
 38941  		isInterleavedBufferAttribute: true,
 38942  
 38943  		get count() {
 38944  
 38945  			return this.data.count;
 38946  
 38947  		},
 38948  
 38949  		get array() {
 38950  
 38951  			return this.data.array;
 38952  
 38953  		},
 38954  
 38955  		setX: function ( index, x ) {
 38956  
 38957  			this.data.array[ index * this.data.stride + this.offset ] = x;
 38958  
 38959  			return this;
 38960  
 38961  		},
 38962  
 38963  		setY: function ( index, y ) {
 38964  
 38965  			this.data.array[ index * this.data.stride + this.offset + 1 ] = y;
 38966  
 38967  			return this;
 38968  
 38969  		},
 38970  
 38971  		setZ: function ( index, z ) {
 38972  
 38973  			this.data.array[ index * this.data.stride + this.offset + 2 ] = z;
 38974  
 38975  			return this;
 38976  
 38977  		},
 38978  
 38979  		setW: function ( index, w ) {
 38980  
 38981  			this.data.array[ index * this.data.stride + this.offset + 3 ] = w;
 38982  
 38983  			return this;
 38984  
 38985  		},
 38986  
 38987  		getX: function ( index ) {
 38988  
 38989  			return this.data.array[ index * this.data.stride + this.offset ];
 38990  
 38991  		},
 38992  
 38993  		getY: function ( index ) {
 38994  
 38995  			return this.data.array[ index * this.data.stride + this.offset + 1 ];
 38996  
 38997  		},
 38998  
 38999  		getZ: function ( index ) {
 39000  
 39001  			return this.data.array[ index * this.data.stride + this.offset + 2 ];
 39002  
 39003  		},
 39004  
 39005  		getW: function ( index ) {
 39006  
 39007  			return this.data.array[ index * this.data.stride + this.offset + 3 ];
 39008  
 39009  		},
 39010  
 39011  		setXY: function ( index, x, y ) {
 39012  
 39013  			index = index * this.data.stride + this.offset;
 39014  
 39015  			this.data.array[ index + 0 ] = x;
 39016  			this.data.array[ index + 1 ] = y;
 39017  
 39018  			return this;
 39019  
 39020  		},
 39021  
 39022  		setXYZ: function ( index, x, y, z ) {
 39023  
 39024  			index = index * this.data.stride + this.offset;
 39025  
 39026  			this.data.array[ index + 0 ] = x;
 39027  			this.data.array[ index + 1 ] = y;
 39028  			this.data.array[ index + 2 ] = z;
 39029  
 39030  			return this;
 39031  
 39032  		},
 39033  
 39034  		setXYZW: function ( index, x, y, z, w ) {
 39035  
 39036  			index = index * this.data.stride + this.offset;
 39037  
 39038  			this.data.array[ index + 0 ] = x;
 39039  			this.data.array[ index + 1 ] = y;
 39040  			this.data.array[ index + 2 ] = z;
 39041  			this.data.array[ index + 3 ] = w;
 39042  
 39043  			return this;
 39044  
 39045  		}
 39046  
 39047  	};
 39048  
 39049  	/**
 39050  	 * @author benaadams / https://twitter.com/ben_a_adams
 39051  	 */
 39052  
 39053  	function InterleavedBuffer( array, stride ) {
 39054  
 39055  		this.uuid = _Math.generateUUID();
 39056  
 39057  		this.array = array;
 39058  		this.stride = stride;
 39059  		this.count = array !== undefined ? array.length / stride : 0;
 39060  
 39061  		this.dynamic = false;
 39062  		this.updateRange = { offset: 0, count: - 1 };
 39063  
 39064  		this.onUploadCallback = function () {};
 39065  
 39066  		this.version = 0;
 39067  
 39068  	}
 39069  
 39070  	InterleavedBuffer.prototype = {
 39071  
 39072  		constructor: InterleavedBuffer,
 39073  
 39074  		isInterleavedBuffer: true,
 39075  
 39076  		set needsUpdate( value ) {
 39077  
 39078  			if ( value === true ) this.version ++;
 39079  
 39080  		},
 39081  
 39082  		setArray: function ( array ) {
 39083  
 39084  			if ( Array.isArray( array ) ) {
 39085  
 39086  				throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
 39087  
 39088  			}
 39089  
 39090  			this.count = array !== undefined ? array.length / this.stride : 0;
 39091  			this.array = array;
 39092  
 39093  		},
 39094  
 39095  		setDynamic: function ( value ) {
 39096  
 39097  			this.dynamic = value;
 39098  
 39099  			return this;
 39100  
 39101  		},
 39102  
 39103  		copy: function ( source ) {
 39104  
 39105  			this.array = new source.array.constructor( source.array );
 39106  			this.count = source.count;
 39107  			this.stride = source.stride;
 39108  			this.dynamic = source.dynamic;
 39109  
 39110  			return this;
 39111  
 39112  		},
 39113  
 39114  		copyAt: function ( index1, attribute, index2 ) {
 39115  
 39116  			index1 *= this.stride;
 39117  			index2 *= attribute.stride;
 39118  
 39119  			for ( var i = 0, l = this.stride; i < l; i ++ ) {
 39120  
 39121  				this.array[ index1 + i ] = attribute.array[ index2 + i ];
 39122  
 39123  			}
 39124  
 39125  			return this;
 39126  
 39127  		},
 39128  
 39129  		set: function ( value, offset ) {
 39130  
 39131  			if ( offset === undefined ) offset = 0;
 39132  
 39133  			this.array.set( value, offset );
 39134  
 39135  			return this;
 39136  
 39137  		},
 39138  
 39139  		clone: function () {
 39140  
 39141  			return new this.constructor().copy( this );
 39142  
 39143  		},
 39144  
 39145  		onUpload: function ( callback ) {
 39146  
 39147  			this.onUploadCallback = callback;
 39148  
 39149  			return this;
 39150  
 39151  		}
 39152  
 39153  	};
 39154  
 39155  	/**
 39156  	 * @author benaadams / https://twitter.com/ben_a_adams
 39157  	 */
 39158  
 39159  	function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) {
 39160  
 39161  		InterleavedBuffer.call( this, array, stride );
 39162  
 39163  		this.meshPerAttribute = meshPerAttribute || 1;
 39164  
 39165  	}
 39166  
 39167  	InstancedInterleavedBuffer.prototype = Object.create( InterleavedBuffer.prototype );
 39168  	InstancedInterleavedBuffer.prototype.constructor = InstancedInterleavedBuffer;
 39169  
 39170  	InstancedInterleavedBuffer.prototype.isInstancedInterleavedBuffer = true;
 39171  
 39172  	InstancedInterleavedBuffer.prototype.copy = function ( source ) {
 39173  
 39174  		InterleavedBuffer.prototype.copy.call( this, source );
 39175  
 39176  		this.meshPerAttribute = source.meshPerAttribute;
 39177  
 39178  		return this;
 39179  
 39180  	};
 39181  
 39182  	/**
 39183  	 * @author benaadams / https://twitter.com/ben_a_adams
 39184  	 */
 39185  
 39186  	function InstancedBufferAttribute( array, itemSize, meshPerAttribute ) {
 39187  
 39188  		BufferAttribute.call( this, array, itemSize );
 39189  
 39190  		this.meshPerAttribute = meshPerAttribute || 1;
 39191  
 39192  	}
 39193  
 39194  	InstancedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );
 39195  	InstancedBufferAttribute.prototype.constructor = InstancedBufferAttribute;
 39196  
 39197  	InstancedBufferAttribute.prototype.isInstancedBufferAttribute = true;
 39198  
 39199  	InstancedBufferAttribute.prototype.copy = function ( source ) {
 39200  
 39201  		BufferAttribute.prototype.copy.call( this, source );
 39202  
 39203  		this.meshPerAttribute = source.meshPerAttribute;
 39204  
 39205  		return this;
 39206  
 39207  	};
 39208  
 39209  	/**
 39210  	 * @author mrdoob / http://mrdoob.com/
 39211  	 * @author bhouston / http://clara.io/
 39212  	 * @author stephomi / http://stephaneginier.com/
 39213  	 */
 39214  
 39215  	function Raycaster( origin, direction, near, far ) {
 39216  
 39217  		this.ray = new Ray( origin, direction );
 39218  		// direction is assumed to be normalized (for accurate distance calculations)
 39219  
 39220  		this.near = near || 0;
 39221  		this.far = far || Infinity;
 39222  
 39223  		this.params = {
 39224  			Mesh: {},
 39225  			Line: {},
 39226  			LOD: {},
 39227  			Points: { threshold: 1 },
 39228  			Sprite: {}
 39229  		};
 39230  
 39231  		Object.defineProperties( this.params, {
 39232  			PointCloud: {
 39233  				get: function () {
 39234  					console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' );
 39235  					return this.Points;
 39236  				}
 39237  			}
 39238  		} );
 39239  
 39240  	}
 39241  
 39242  	function ascSort( a, b ) {
 39243  
 39244  		return a.distance - b.distance;
 39245  
 39246  	}
 39247  
 39248  	function intersectObject( object, raycaster, intersects, recursive ) {
 39249  
 39250  		if ( object.visible === false ) return;
 39251  
 39252  		object.raycast( raycaster, intersects );
 39253  
 39254  		if ( recursive === true ) {
 39255  
 39256  			var children = object.children;
 39257  
 39258  			for ( var i = 0, l = children.length; i < l; i ++ ) {
 39259  
 39260  				intersectObject( children[ i ], raycaster, intersects, true );
 39261  
 39262  			}
 39263  
 39264  		}
 39265  
 39266  	}
 39267  
 39268  	//
 39269  
 39270  	Raycaster.prototype = {
 39271  
 39272  		constructor: Raycaster,
 39273  
 39274  		linePrecision: 1,
 39275  
 39276  		set: function ( origin, direction ) {
 39277  
 39278  			// direction is assumed to be normalized (for accurate distance calculations)
 39279  
 39280  			this.ray.set( origin, direction );
 39281  
 39282  		},
 39283  
 39284  		setFromCamera: function ( coords, camera ) {
 39285  
 39286  			if ( (camera && camera.isPerspectiveCamera) ) {
 39287  
 39288  				this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
 39289  				this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
 39290  
 39291  			} else if ( (camera && camera.isOrthographicCamera) ) {
 39292  
 39293  				this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
 39294  				this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
 39295  
 39296  			} else {
 39297  
 39298  				console.error( 'THREE.Raycaster: Unsupported camera type.' );
 39299  
 39300  			}
 39301  
 39302  		},
 39303  
 39304  		intersectObject: function ( object, recursive ) {
 39305  
 39306  			var intersects = [];
 39307  
 39308  			intersectObject( object, this, intersects, recursive );
 39309  
 39310  			intersects.sort( ascSort );
 39311  
 39312  			return intersects;
 39313  
 39314  		},
 39315  
 39316  		intersectObjects: function ( objects, recursive ) {
 39317  
 39318  			var intersects = [];
 39319  
 39320  			if ( Array.isArray( objects ) === false ) {
 39321  
 39322  				console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );
 39323  				return intersects;
 39324  
 39325  			}
 39326  
 39327  			for ( var i = 0, l = objects.length; i < l; i ++ ) {
 39328  
 39329  				intersectObject( objects[ i ], this, intersects, recursive );
 39330  
 39331  			}
 39332  
 39333  			intersects.sort( ascSort );
 39334  
 39335  			return intersects;
 39336  
 39337  		}
 39338  
 39339  	};
 39340  
 39341  	/**
 39342  	 * @author alteredq / http://alteredqualia.com/
 39343  	 */
 39344  
 39345  	function Clock( autoStart ) {
 39346  
 39347  		this.autoStart = ( autoStart !== undefined ) ? autoStart : true;
 39348  
 39349  		this.startTime = 0;
 39350  		this.oldTime = 0;
 39351  		this.elapsedTime = 0;
 39352  
 39353  		this.running = false;
 39354  
 39355  	}
 39356  
 39357  	Clock.prototype = {
 39358  
 39359  		constructor: Clock,
 39360  
 39361  		start: function () {
 39362  
 39363  			this.startTime = ( performance || Date ).now();
 39364  
 39365  			this.oldTime = this.startTime;
 39366  			this.elapsedTime = 0;
 39367  			this.running = true;
 39368  
 39369  		},
 39370  
 39371  		stop: function () {
 39372  
 39373  			this.getElapsedTime();
 39374  			this.running = false;
 39375  
 39376  		},
 39377  
 39378  		getElapsedTime: function () {
 39379  
 39380  			this.getDelta();
 39381  			return this.elapsedTime;
 39382  
 39383  		},
 39384  
 39385  		getDelta: function () {
 39386  
 39387  			var diff = 0;
 39388  
 39389  			if ( this.autoStart && ! this.running ) {
 39390  
 39391  				this.start();
 39392  
 39393  			}
 39394  
 39395  			if ( this.running ) {
 39396  
 39397  				var newTime = ( performance || Date ).now();
 39398  
 39399  				diff = ( newTime - this.oldTime ) / 1000;
 39400  				this.oldTime = newTime;
 39401  
 39402  				this.elapsedTime += diff;
 39403  
 39404  			}
 39405  
 39406  			return diff;
 39407  
 39408  		}
 39409  
 39410  	};
 39411  
 39412  	/**
 39413  	 * @author bhouston / http://clara.io
 39414  	 * @author WestLangley / http://github.com/WestLangley
 39415  	 *
 39416  	 * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
 39417  	 *
 39418  	 * The poles (phi) are at the positive and negative y axis.
 39419  	 * The equator starts at positive z.
 39420  	 */
 39421  
 39422  	function Spherical( radius, phi, theta ) {
 39423  
 39424  		this.radius = ( radius !== undefined ) ? radius : 1.0;
 39425  		this.phi = ( phi !== undefined ) ? phi : 0; // up / down towards top and bottom pole
 39426  		this.theta = ( theta !== undefined ) ? theta : 0; // around the equator of the sphere
 39427  
 39428  		return this;
 39429  
 39430  	}
 39431  
 39432  	Spherical.prototype = {
 39433  
 39434  		constructor: Spherical,
 39435  
 39436  		set: function ( radius, phi, theta ) {
 39437  
 39438  			this.radius = radius;
 39439  			this.phi = phi;
 39440  			this.theta = theta;
 39441  
 39442  			return this;
 39443  
 39444  		},
 39445  
 39446  		clone: function () {
 39447  
 39448  			return new this.constructor().copy( this );
 39449  
 39450  		},
 39451  
 39452  		copy: function ( other ) {
 39453  
 39454  			this.radius = other.radius;
 39455  			this.phi = other.phi;
 39456  			this.theta = other.theta;
 39457  
 39458  			return this;
 39459  
 39460  		},
 39461  
 39462  		// restrict phi to be betwee EPS and PI-EPS
 39463  		makeSafe: function() {
 39464  
 39465  			var EPS = 0.000001;
 39466  			this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );
 39467  
 39468  			return this;
 39469  
 39470  		},
 39471  
 39472  		setFromVector3: function( vec3 ) {
 39473  
 39474  			this.radius = vec3.length();
 39475  
 39476  			if ( this.radius === 0 ) {
 39477  
 39478  				this.theta = 0;
 39479  				this.phi = 0;
 39480  
 39481  			} else {
 39482  
 39483  				this.theta = Math.atan2( vec3.x, vec3.z ); // equator angle around y-up axis
 39484  				this.phi = Math.acos( _Math.clamp( vec3.y / this.radius, - 1, 1 ) ); // polar angle
 39485  
 39486  			}
 39487  
 39488  			return this;
 39489  
 39490  		}
 39491  
 39492  	};
 39493  
 39494  	/**
 39495  	 * @author Mugen87 / https://github.com/Mugen87
 39496  	 *
 39497  	 * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
 39498  	 *
 39499  	 */
 39500  
 39501  	function Cylindrical( radius, theta, y ) {
 39502  
 39503  		this.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane
 39504  		this.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis
 39505  		this.y = ( y !== undefined ) ? y : 0; // height above the x-z plane
 39506  
 39507  		return this;
 39508  
 39509  	}
 39510  
 39511  	Cylindrical.prototype = {
 39512  
 39513  		constructor: Cylindrical,
 39514  
 39515  		set: function ( radius, theta, y ) {
 39516  
 39517  			this.radius = radius;
 39518  			this.theta = theta;
 39519  			this.y = y;
 39520  
 39521  			return this;
 39522  
 39523  		},
 39524  
 39525  		clone: function () {
 39526  
 39527  			return new this.constructor().copy( this );
 39528  
 39529  		},
 39530  
 39531  		copy: function ( other ) {
 39532  
 39533  			this.radius = other.radius;
 39534  			this.theta = other.theta;
 39535  			this.y = other.y;
 39536  
 39537  			return this;
 39538  
 39539  		},
 39540  
 39541  		setFromVector3: function( vec3 ) {
 39542  
 39543  			this.radius = Math.sqrt( vec3.x * vec3.x + vec3.z * vec3.z );
 39544  			this.theta = Math.atan2( vec3.x, vec3.z );
 39545  			this.y = vec3.y;
 39546  
 39547  			return this;
 39548  
 39549  		}
 39550  
 39551  	};
 39552  
 39553  	/**
 39554  	 * @author alteredq / http://alteredqualia.com/
 39555  	 */
 39556  
 39557  	function MorphBlendMesh( geometry, material ) {
 39558  
 39559  		Mesh.call( this, geometry, material );
 39560  
 39561  		this.animationsMap = {};
 39562  		this.animationsList = [];
 39563  
 39564  		// prepare default animation
 39565  		// (all frames played together in 1 second)
 39566  
 39567  		var numFrames = this.geometry.morphTargets.length;
 39568  
 39569  		var name = "__default";
 39570  
 39571  		var startFrame = 0;
 39572  		var endFrame = numFrames - 1;
 39573  
 39574  		var fps = numFrames / 1;
 39575  
 39576  		this.createAnimation( name, startFrame, endFrame, fps );
 39577  		this.setAnimationWeight( name, 1 );
 39578  
 39579  	}
 39580  
 39581  	MorphBlendMesh.prototype = Object.create( Mesh.prototype );
 39582  	MorphBlendMesh.prototype.constructor = MorphBlendMesh;
 39583  
 39584  	MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) {
 39585  
 39586  		var animation = {
 39587  
 39588  			start: start,
 39589  			end: end,
 39590  
 39591  			length: end - start + 1,
 39592  
 39593  			fps: fps,
 39594  			duration: ( end - start ) / fps,
 39595  
 39596  			lastFrame: 0,
 39597  			currentFrame: 0,
 39598  
 39599  			active: false,
 39600  
 39601  			time: 0,
 39602  			direction: 1,
 39603  			weight: 1,
 39604  
 39605  			directionBackwards: false,
 39606  			mirroredLoop: false
 39607  
 39608  		};
 39609  
 39610  		this.animationsMap[ name ] = animation;
 39611  		this.animationsList.push( animation );
 39612  
 39613  	};
 39614  
 39615  	MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) {
 39616  
 39617  		var pattern = /([a-z]+)_?(\d+)/i;
 39618  
 39619  		var firstAnimation, frameRanges = {};
 39620  
 39621  		var geometry = this.geometry;
 39622  
 39623  		for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) {
 39624  
 39625  			var morph = geometry.morphTargets[ i ];
 39626  			var chunks = morph.name.match( pattern );
 39627  
 39628  			if ( chunks && chunks.length > 1 ) {
 39629  
 39630  				var name = chunks[ 1 ];
 39631  
 39632  				if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity };
 39633  
 39634  				var range = frameRanges[ name ];
 39635  
 39636  				if ( i < range.start ) range.start = i;
 39637  				if ( i > range.end ) range.end = i;
 39638  
 39639  				if ( ! firstAnimation ) firstAnimation = name;
 39640  
 39641  			}
 39642  
 39643  		}
 39644  
 39645  		for ( var name in frameRanges ) {
 39646  
 39647  			var range = frameRanges[ name ];
 39648  			this.createAnimation( name, range.start, range.end, fps );
 39649  
 39650  		}
 39651  
 39652  		this.firstAnimation = firstAnimation;
 39653  
 39654  	};
 39655  
 39656  	MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) {
 39657  
 39658  		var animation = this.animationsMap[ name ];
 39659  
 39660  		if ( animation ) {
 39661  
 39662  			animation.direction = 1;
 39663  			animation.directionBackwards = false;
 39664  
 39665  		}
 39666  
 39667  	};
 39668  
 39669  	MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) {
 39670  
 39671  		var animation = this.animationsMap[ name ];
 39672  
 39673  		if ( animation ) {
 39674  
 39675  			animation.direction = - 1;
 39676  			animation.directionBackwards = true;
 39677  
 39678  		}
 39679  
 39680  	};
 39681  
 39682  	MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) {
 39683  
 39684  		var animation = this.animationsMap[ name ];
 39685  
 39686  		if ( animation ) {
 39687  
 39688  			animation.fps = fps;
 39689  			animation.duration = ( animation.end - animation.start ) / animation.fps;
 39690  
 39691  		}
 39692  
 39693  	};
 39694  
 39695  	MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) {
 39696  
 39697  		var animation = this.animationsMap[ name ];
 39698  
 39699  		if ( animation ) {
 39700  
 39701  			animation.duration = duration;
 39702  			animation.fps = ( animation.end - animation.start ) / animation.duration;
 39703  
 39704  		}
 39705  
 39706  	};
 39707  
 39708  	MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) {
 39709  
 39710  		var animation = this.animationsMap[ name ];
 39711  
 39712  		if ( animation ) {
 39713  
 39714  			animation.weight = weight;
 39715  
 39716  		}
 39717  
 39718  	};
 39719  
 39720  	MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) {
 39721  
 39722  		var animation = this.animationsMap[ name ];
 39723  
 39724  		if ( animation ) {
 39725  
 39726  			animation.time = time;
 39727  
 39728  		}
 39729  
 39730  	};
 39731  
 39732  	MorphBlendMesh.prototype.getAnimationTime = function ( name ) {
 39733  
 39734  		var time = 0;
 39735  
 39736  		var animation = this.animationsMap[ name ];
 39737  
 39738  		if ( animation ) {
 39739  
 39740  			time = animation.time;
 39741  
 39742  		}
 39743  
 39744  		return time;
 39745  
 39746  	};
 39747  
 39748  	MorphBlendMesh.prototype.getAnimationDuration = function ( name ) {
 39749  
 39750  		var duration = - 1;
 39751  
 39752  		var animation = this.animationsMap[ name ];
 39753  
 39754  		if ( animation ) {
 39755  
 39756  			duration = animation.duration;
 39757  
 39758  		}
 39759  
 39760  		return duration;
 39761  
 39762  	};
 39763  
 39764  	MorphBlendMesh.prototype.playAnimation = function ( name ) {
 39765  
 39766  		var animation = this.animationsMap[ name ];
 39767  
 39768  		if ( animation ) {
 39769  
 39770  			animation.time = 0;
 39771  			animation.active = true;
 39772  
 39773  		} else {
 39774  
 39775  			console.warn( "THREE.MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()" );
 39776  
 39777  		}
 39778  
 39779  	};
 39780  
 39781  	MorphBlendMesh.prototype.stopAnimation = function ( name ) {
 39782  
 39783  		var animation = this.animationsMap[ name ];
 39784  
 39785  		if ( animation ) {
 39786  
 39787  			animation.active = false;
 39788  
 39789  		}
 39790  
 39791  	};
 39792  
 39793  	MorphBlendMesh.prototype.update = function ( delta ) {
 39794  
 39795  		for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) {
 39796  
 39797  			var animation = this.animationsList[ i ];
 39798  
 39799  			if ( ! animation.active ) continue;
 39800  
 39801  			var frameTime = animation.duration / animation.length;
 39802  
 39803  			animation.time += animation.direction * delta;
 39804  
 39805  			if ( animation.mirroredLoop ) {
 39806  
 39807  				if ( animation.time > animation.duration || animation.time < 0 ) {
 39808  
 39809  					animation.direction *= - 1;
 39810  
 39811  					if ( animation.time > animation.duration ) {
 39812  
 39813  						animation.time = animation.duration;
 39814  						animation.directionBackwards = true;
 39815  
 39816  					}
 39817  
 39818  					if ( animation.time < 0 ) {
 39819  
 39820  						animation.time = 0;
 39821  						animation.directionBackwards = false;
 39822  
 39823  					}
 39824  
 39825  				}
 39826  
 39827  			} else {
 39828  
 39829  				animation.time = animation.time % animation.duration;
 39830  
 39831  				if ( animation.time < 0 ) animation.time += animation.duration;
 39832  
 39833  			}
 39834  
 39835  			var keyframe = animation.start + _Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 );
 39836  			var weight = animation.weight;
 39837  
 39838  			if ( keyframe !== animation.currentFrame ) {
 39839  
 39840  				this.morphTargetInfluences[ animation.lastFrame ] = 0;
 39841  				this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight;
 39842  
 39843  				this.morphTargetInfluences[ keyframe ] = 0;
 39844  
 39845  				animation.lastFrame = animation.currentFrame;
 39846  				animation.currentFrame = keyframe;
 39847  
 39848  			}
 39849  
 39850  			var mix = ( animation.time % frameTime ) / frameTime;
 39851  
 39852  			if ( animation.directionBackwards ) mix = 1 - mix;
 39853  
 39854  			if ( animation.currentFrame !== animation.lastFrame ) {
 39855  
 39856  				this.morphTargetInfluences[ animation.currentFrame ] = mix * weight;
 39857  				this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight;
 39858  
 39859  			} else {
 39860  
 39861  				this.morphTargetInfluences[ animation.currentFrame ] = weight;
 39862  
 39863  			}
 39864  
 39865  		}
 39866  
 39867  	};
 39868  
 39869  	/**
 39870  	 * @author alteredq / http://alteredqualia.com/
 39871  	 */
 39872  
 39873  	function ImmediateRenderObject( material ) {
 39874  
 39875  		Object3D.call( this );
 39876  
 39877  		this.material = material;
 39878  		this.render = function ( renderCallback ) {};
 39879  
 39880  	}
 39881  
 39882  	ImmediateRenderObject.prototype = Object.create( Object3D.prototype );
 39883  	ImmediateRenderObject.prototype.constructor = ImmediateRenderObject;
 39884  
 39885  	ImmediateRenderObject.prototype.isImmediateRenderObject = true;
 39886  
 39887  	/**
 39888  	 * @author mrdoob / http://mrdoob.com/
 39889  	 * @author WestLangley / http://github.com/WestLangley
 39890  	*/
 39891  
 39892  	function VertexNormalsHelper( object, size, hex, linewidth ) {
 39893  
 39894  		this.object = object;
 39895  
 39896  		this.size = ( size !== undefined ) ? size : 1;
 39897  
 39898  		var color = ( hex !== undefined ) ? hex : 0xff0000;
 39899  
 39900  		var width = ( linewidth !== undefined ) ? linewidth : 1;
 39901  
 39902  		//
 39903  
 39904  		var nNormals = 0;
 39905  
 39906  		var objGeometry = this.object.geometry;
 39907  
 39908  		if ( objGeometry && objGeometry.isGeometry ) {
 39909  
 39910  			nNormals = objGeometry.faces.length * 3;
 39911  
 39912  		} else if ( objGeometry && objGeometry.isBufferGeometry ) {
 39913  
 39914  			nNormals = objGeometry.attributes.normal.count;
 39915  
 39916  		}
 39917  
 39918  		//
 39919  
 39920  		var geometry = new BufferGeometry();
 39921  
 39922  		var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 );
 39923  
 39924  		geometry.addAttribute( 'position', positions );
 39925  
 39926  		LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) );
 39927  
 39928  		//
 39929  
 39930  		this.matrixAutoUpdate = false;
 39931  
 39932  		this.update();
 39933  
 39934  	}
 39935  
 39936  	VertexNormalsHelper.prototype = Object.create( LineSegments.prototype );
 39937  	VertexNormalsHelper.prototype.constructor = VertexNormalsHelper;
 39938  
 39939  	VertexNormalsHelper.prototype.update = ( function () {
 39940  
 39941  		var v1 = new Vector3();
 39942  		var v2 = new Vector3();
 39943  		var normalMatrix = new Matrix3();
 39944  
 39945  		return function update() {
 39946  
 39947  			var keys = [ 'a', 'b', 'c' ];
 39948  
 39949  			this.object.updateMatrixWorld( true );
 39950  
 39951  			normalMatrix.getNormalMatrix( this.object.matrixWorld );
 39952  
 39953  			var matrixWorld = this.object.matrixWorld;
 39954  
 39955  			var position = this.geometry.attributes.position;
 39956  
 39957  			//
 39958  
 39959  			var objGeometry = this.object.geometry;
 39960  
 39961  			if ( objGeometry && objGeometry.isGeometry ) {
 39962  
 39963  				var vertices = objGeometry.vertices;
 39964  
 39965  				var faces = objGeometry.faces;
 39966  
 39967  				var idx = 0;
 39968  
 39969  				for ( var i = 0, l = faces.length; i < l; i ++ ) {
 39970  
 39971  					var face = faces[ i ];
 39972  
 39973  					for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
 39974  
 39975  						var vertex = vertices[ face[ keys[ j ] ] ];
 39976  
 39977  						var normal = face.vertexNormals[ j ];
 39978  
 39979  						v1.copy( vertex ).applyMatrix4( matrixWorld );
 39980  
 39981  						v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );
 39982  
 39983  						position.setXYZ( idx, v1.x, v1.y, v1.z );
 39984  
 39985  						idx = idx + 1;
 39986  
 39987  						position.setXYZ( idx, v2.x, v2.y, v2.z );
 39988  
 39989  						idx = idx + 1;
 39990  
 39991  					}
 39992  
 39993  				}
 39994  
 39995  			} else if ( objGeometry && objGeometry.isBufferGeometry ) {
 39996  
 39997  				var objPos = objGeometry.attributes.position;
 39998  
 39999  				var objNorm = objGeometry.attributes.normal;
 40000  
 40001  				var idx = 0;
 40002  
 40003  				// for simplicity, ignore index and drawcalls, and render every normal
 40004  
 40005  				for ( var j = 0, jl = objPos.count; j < jl; j ++ ) {
 40006  
 40007  					v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld );
 40008  
 40009  					v2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) );
 40010  
 40011  					v2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );
 40012  
 40013  					position.setXYZ( idx, v1.x, v1.y, v1.z );
 40014  
 40015  					idx = idx + 1;
 40016  
 40017  					position.setXYZ( idx, v2.x, v2.y, v2.z );
 40018  
 40019  					idx = idx + 1;
 40020  
 40021  				}
 40022  
 40023  			}
 40024  
 40025  			position.needsUpdate = true;
 40026  
 40027  			return this;
 40028  
 40029  		};
 40030  
 40031  	}() );
 40032  
 40033  	/**
 40034  	 * @author alteredq / http://alteredqualia.com/
 40035  	 * @author mrdoob / http://mrdoob.com/
 40036  	 * @author WestLangley / http://github.com/WestLangley
 40037  	*/
 40038  
 40039  	function SpotLightHelper( light ) {
 40040  
 40041  		Object3D.call( this );
 40042  
 40043  		this.light = light;
 40044  		this.light.updateMatrixWorld();
 40045  
 40046  		this.matrix = light.matrixWorld;
 40047  		this.matrixAutoUpdate = false;
 40048  
 40049  		var geometry = new BufferGeometry();
 40050  
 40051  		var positions = [
 40052  			0, 0, 0,   0,   0,   1,
 40053  			0, 0, 0,   1,   0,   1,
 40054  			0, 0, 0, - 1,   0,   1,
 40055  			0, 0, 0,   0,   1,   1,
 40056  			0, 0, 0,   0, - 1,   1
 40057  		];
 40058  
 40059  		for ( var i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {
 40060  
 40061  			var p1 = ( i / l ) * Math.PI * 2;
 40062  			var p2 = ( j / l ) * Math.PI * 2;
 40063  
 40064  			positions.push(
 40065  				Math.cos( p1 ), Math.sin( p1 ), 1,
 40066  				Math.cos( p2 ), Math.sin( p2 ), 1
 40067  			);
 40068  
 40069  		}
 40070  
 40071  		geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
 40072  
 40073  		var material = new LineBasicMaterial( { fog: false } );
 40074  
 40075  		this.cone = new LineSegments( geometry, material );
 40076  		this.add( this.cone );
 40077  
 40078  		this.update();
 40079  
 40080  	}
 40081  
 40082  	SpotLightHelper.prototype = Object.create( Object3D.prototype );
 40083  	SpotLightHelper.prototype.constructor = SpotLightHelper;
 40084  
 40085  	SpotLightHelper.prototype.dispose = function () {
 40086  
 40087  		this.cone.geometry.dispose();
 40088  		this.cone.material.dispose();
 40089  
 40090  	};
 40091  
 40092  	SpotLightHelper.prototype.update = function () {
 40093  
 40094  		var vector = new Vector3();
 40095  		var vector2 = new Vector3();
 40096  
 40097  		return function update() {
 40098  
 40099  			var coneLength = this.light.distance ? this.light.distance : 1000;
 40100  			var coneWidth = coneLength * Math.tan( this.light.angle );
 40101  
 40102  			this.cone.scale.set( coneWidth, coneWidth, coneLength );
 40103  
 40104  			vector.setFromMatrixPosition( this.light.matrixWorld );
 40105  			vector2.setFromMatrixPosition( this.light.target.matrixWorld );
 40106  
 40107  			this.cone.lookAt( vector2.sub( vector ) );
 40108  
 40109  			this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
 40110  
 40111  		};
 40112  
 40113  	}();
 40114  
 40115  	/**
 40116  	 * @author Sean Griffin / http://twitter.com/sgrif
 40117  	 * @author Michael Guerrero / http://realitymeltdown.com
 40118  	 * @author mrdoob / http://mrdoob.com/
 40119  	 * @author ikerr / http://verold.com
 40120  	 * @author Mugen87 / https://github.com/Mugen87
 40121  	 */
 40122  
 40123  	function SkeletonHelper( object ) {
 40124  
 40125  		this.bones = this.getBoneList( object );
 40126  
 40127  		var geometry = new BufferGeometry();
 40128  
 40129  		var vertices = [];
 40130  		var colors = [];
 40131  
 40132  		var color1 = new Color( 0, 0, 1 );
 40133  		var color2 = new Color( 0, 1, 0 );
 40134  
 40135  		for ( var i = 0; i < this.bones.length; i ++ ) {
 40136  
 40137  			var bone = this.bones[ i ];
 40138  
 40139  			if ( bone.parent && bone.parent.isBone ) {
 40140  
 40141  				vertices.push( 0, 0, 0 );
 40142  				vertices.push( 0, 0, 0 );
 40143  				colors.push( color1.r, color1.g, color1.b );
 40144  				colors.push( color2.r, color2.g, color2.b );
 40145  
 40146  			}
 40147  
 40148  		}
 40149  
 40150  		geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 40151  		geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
 40152  
 40153  		var material = new LineBasicMaterial( { vertexColors: VertexColors, depthTest: false, depthWrite: false, transparent: true } );
 40154  
 40155  		LineSegments.call( this, geometry, material );
 40156  
 40157  		this.root = object;
 40158  
 40159  		this.matrix = object.matrixWorld;
 40160  		this.matrixAutoUpdate = false;
 40161  
 40162  		this.update();
 40163  
 40164  	}
 40165  
 40166  
 40167  	SkeletonHelper.prototype = Object.create( LineSegments.prototype );
 40168  	SkeletonHelper.prototype.constructor = SkeletonHelper;
 40169  
 40170  	SkeletonHelper.prototype.getBoneList = function( object ) {
 40171  
 40172  		var boneList = [];
 40173  
 40174  		if ( object && object.isBone ) {
 40175  
 40176  			boneList.push( object );
 40177  
 40178  		}
 40179  
 40180  		for ( var i = 0; i < object.children.length; i ++ ) {
 40181  
 40182  			boneList.push.apply( boneList, this.getBoneList( object.children[ i ] ) );
 40183  
 40184  		}
 40185  
 40186  		return boneList;
 40187  
 40188  	};
 40189  
 40190  	SkeletonHelper.prototype.update = function () {
 40191  
 40192  		var vector = new Vector3();
 40193  
 40194  		var boneMatrix = new Matrix4();
 40195  		var matrixWorldInv = new Matrix4();
 40196  
 40197  		return function update() {
 40198  
 40199  			var geometry = this.geometry;
 40200  			var position = geometry.getAttribute( 'position' );
 40201  
 40202  			matrixWorldInv.getInverse( this.root.matrixWorld );
 40203  
 40204  			for ( var i = 0, j = 0; i < this.bones.length; i ++ ) {
 40205  
 40206  				var bone = this.bones[ i ];
 40207  
 40208  				if ( bone.parent && bone.parent.isBone ) {
 40209  
 40210  					boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld );
 40211  					vector.setFromMatrixPosition( boneMatrix );
 40212  					position.setXYZ( j, vector.x, vector.y, vector.z );
 40213  
 40214  					boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld );
 40215  					vector.setFromMatrixPosition( boneMatrix );
 40216  					position.setXYZ( j + 1, vector.x, vector.y, vector.z );
 40217  
 40218  					j += 2;
 40219  
 40220  				}
 40221  
 40222  			}
 40223  
 40224  			geometry.getAttribute( 'position' ).needsUpdate = true;
 40225  
 40226  		};
 40227  
 40228  	}();
 40229  
 40230  	/**
 40231  	 * @author alteredq / http://alteredqualia.com/
 40232  	 * @author mrdoob / http://mrdoob.com/
 40233  	 */
 40234  
 40235  	function PointLightHelper( light, sphereSize ) {
 40236  
 40237  		this.light = light;
 40238  		this.light.updateMatrixWorld();
 40239  
 40240  		var geometry = new SphereBufferGeometry( sphereSize, 4, 2 );
 40241  		var material = new MeshBasicMaterial( { wireframe: true, fog: false } );
 40242  		material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
 40243  
 40244  		Mesh.call( this, geometry, material );
 40245  
 40246  		this.matrix = this.light.matrixWorld;
 40247  		this.matrixAutoUpdate = false;
 40248  
 40249  		/*
 40250  		var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );
 40251  		var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );
 40252  
 40253  		this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );
 40254  		this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );
 40255  
 40256  		var d = light.distance;
 40257  
 40258  		if ( d === 0.0 ) {
 40259  
 40260  			this.lightDistance.visible = false;
 40261  
 40262  		} else {
 40263  
 40264  			this.lightDistance.scale.set( d, d, d );
 40265  
 40266  		}
 40267  
 40268  		this.add( this.lightDistance );
 40269  		*/
 40270  
 40271  	}
 40272  
 40273  	PointLightHelper.prototype = Object.create( Mesh.prototype );
 40274  	PointLightHelper.prototype.constructor = PointLightHelper;
 40275  
 40276  	PointLightHelper.prototype.dispose = function () {
 40277  
 40278  		this.geometry.dispose();
 40279  		this.material.dispose();
 40280  
 40281  	};
 40282  
 40283  	PointLightHelper.prototype.update = function () {
 40284  
 40285  		this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
 40286  
 40287  		/*
 40288  		var d = this.light.distance;
 40289  
 40290  		if ( d === 0.0 ) {
 40291  
 40292  			this.lightDistance.visible = false;
 40293  
 40294  		} else {
 40295  
 40296  			this.lightDistance.visible = true;
 40297  			this.lightDistance.scale.set( d, d, d );
 40298  
 40299  		}
 40300  		*/
 40301  
 40302  	};
 40303  
 40304  	/**
 40305  	 * @author abelnation / http://github.com/abelnation
 40306  	 * @author Mugen87 / http://github.com/Mugen87
 40307  	 */
 40308  
 40309  	function RectAreaLightHelper( light ) {
 40310  
 40311  		Object3D.call( this );
 40312  
 40313  		this.light = light;
 40314  		this.light.updateMatrixWorld();
 40315  
 40316  		var materialFront = new MeshBasicMaterial( {
 40317  			color: light.color,
 40318  			fog: false
 40319  		} );
 40320  
 40321  		var materialBack = new MeshBasicMaterial( {
 40322  			color: light.color,
 40323  			fog: false,
 40324  			wireframe: true
 40325  		} );
 40326  
 40327  		var geometry = new BufferGeometry();
 40328  
 40329  		geometry.addAttribute( 'position', new BufferAttribute( new Float32Array( 6 * 3 ), 3 ) );
 40330  
 40331  		// shows the "front" of the light, e.g. where light comes from
 40332  
 40333  		this.add( new Mesh( geometry, materialFront ) );
 40334  
 40335  		// shows the "back" of the light, which does not emit light
 40336  
 40337  		this.add( new Mesh( geometry, materialBack ) );
 40338  
 40339  		this.update();
 40340  
 40341  	}
 40342  
 40343  	RectAreaLightHelper.prototype = Object.create( Object3D.prototype );
 40344  	RectAreaLightHelper.prototype.constructor = RectAreaLightHelper;
 40345  
 40346  	RectAreaLightHelper.prototype.dispose = function () {
 40347  
 40348  		this.children[ 0 ].geometry.dispose();
 40349  		this.children[ 0 ].material.dispose();
 40350  		this.children[ 1 ].geometry.dispose();
 40351  		this.children[ 1 ].material.dispose();
 40352  
 40353  	};
 40354  
 40355  	RectAreaLightHelper.prototype.update = function () {
 40356  
 40357  		var vector1 = new Vector3();
 40358  		var vector2 = new Vector3();
 40359  
 40360  		return function update() {
 40361  
 40362  			var mesh1 = this.children[ 0 ];
 40363  			var mesh2 = this.children[ 1 ];
 40364  
 40365  			if ( this.light.target ) {
 40366  
 40367  				vector1.setFromMatrixPosition( this.light.matrixWorld );
 40368  				vector2.setFromMatrixPosition( this.light.target.matrixWorld );
 40369  
 40370  				var lookVec = vector2.clone().sub( vector1 );
 40371  				mesh1.lookAt( lookVec );
 40372  				mesh2.lookAt( lookVec );
 40373  
 40374  			}
 40375  
 40376  			// update materials
 40377  
 40378  			mesh1.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
 40379  			mesh2.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
 40380  
 40381  			// calculate new dimensions of the helper
 40382  
 40383  			var hx = this.light.width * 0.5;
 40384  			var hy = this.light.height * 0.5;
 40385  
 40386  			// because the buffer attribute is shared over both geometries, we only have to update once
 40387  
 40388  			var position = mesh1.geometry.getAttribute( 'position' );
 40389  			var array = position.array;
 40390  
 40391  			// first face
 40392  
 40393  			array[  0 ] =   hx; array[  1 ] = - hy; array[  2 ] = 0;
 40394  			array[  3 ] =   hx; array[  4 ] =   hy; array[  5 ] = 0;
 40395  			array[  6 ] = - hx; array[  7 ] =   hy; array[  8 ] = 0;
 40396  
 40397  			// second face
 40398  
 40399  			array[  9 ] = - hx; array[ 10 ] =   hy; array[ 11 ] = 0;
 40400  			array[ 12 ] = - hx; array[ 13 ] = - hy; array[ 14 ] = 0;
 40401  			array[ 15 ] =   hx; array[ 16 ] = - hy; array[ 17 ] = 0;
 40402  
 40403  			position.needsUpdate = true;
 40404  
 40405  		};
 40406  
 40407  	}();
 40408  
 40409  	/**
 40410  	 * @author alteredq / http://alteredqualia.com/
 40411  	 * @author mrdoob / http://mrdoob.com/
 40412  	 * @author Mugen87 / https://github.com/Mugen87
 40413  	 */
 40414  
 40415  	function HemisphereLightHelper( light, size ) {
 40416  
 40417  		Object3D.call( this );
 40418  
 40419  		this.light = light;
 40420  		this.light.updateMatrixWorld();
 40421  
 40422  		this.matrix = light.matrixWorld;
 40423  		this.matrixAutoUpdate = false;
 40424  
 40425  		var geometry = new OctahedronBufferGeometry( size );
 40426  		geometry.rotateY( Math.PI * 0.5 );
 40427  
 40428  		var material = new MeshBasicMaterial( { vertexColors: VertexColors, wireframe: true } );
 40429  
 40430  		var position = geometry.getAttribute( 'position' );
 40431  		var colors = new Float32Array( position.count * 3 );
 40432  
 40433  		geometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) );
 40434  
 40435  		this.add( new Mesh( geometry, material ) );
 40436  
 40437  		this.update();
 40438  
 40439  	}
 40440  
 40441  	HemisphereLightHelper.prototype = Object.create( Object3D.prototype );
 40442  	HemisphereLightHelper.prototype.constructor = HemisphereLightHelper;
 40443  
 40444  	HemisphereLightHelper.prototype.dispose = function () {
 40445  
 40446  		this.children[ 0 ].geometry.dispose();
 40447  		this.children[ 0 ].material.dispose();
 40448  
 40449  	};
 40450  
 40451  	HemisphereLightHelper.prototype.update = function () {
 40452  
 40453  		var vector = new Vector3();
 40454  
 40455  		var color1 = new Color();
 40456  		var color2 = new Color();
 40457  
 40458  		return function update() {
 40459  
 40460  			var mesh = this.children[ 0 ];
 40461  
 40462  			var colors = mesh.geometry.getAttribute( 'color' );
 40463  
 40464  			color1.copy( this.light.color ).multiplyScalar( this.light.intensity );
 40465  			color2.copy( this.light.groundColor ).multiplyScalar( this.light.intensity );
 40466  
 40467  			for ( var i = 0, l = colors.count; i < l; i ++ ) {
 40468  
 40469  				var color = ( i < ( l / 2 ) ) ? color1 : color2;
 40470  
 40471  				colors.setXYZ( i, color.r, color.g, color.b );
 40472  
 40473  			}
 40474  
 40475  			mesh.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() );
 40476  
 40477  			colors.needsUpdate = true;
 40478  
 40479  		};
 40480  
 40481  	}();
 40482  
 40483  	/**
 40484  	 * @author mrdoob / http://mrdoob.com/
 40485  	 */
 40486  
 40487  	function GridHelper( size, divisions, color1, color2 ) {
 40488  
 40489  		size = size || 10;
 40490  		divisions = divisions || 10;
 40491  		color1 = new Color( color1 !== undefined ? color1 : 0x444444 );
 40492  		color2 = new Color( color2 !== undefined ? color2 : 0x888888 );
 40493  
 40494  		var center = divisions / 2;
 40495  		var step = size / divisions;
 40496  		var halfSize = size / 2;
 40497  
 40498  		var vertices = [], colors = [];
 40499  
 40500  		for ( var i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {
 40501  
 40502  			vertices.push( - halfSize, 0, k, halfSize, 0, k );
 40503  			vertices.push( k, 0, - halfSize, k, 0, halfSize );
 40504  
 40505  			var color = i === center ? color1 : color2;
 40506  
 40507  			color.toArray( colors, j ); j += 3;
 40508  			color.toArray( colors, j ); j += 3;
 40509  			color.toArray( colors, j ); j += 3;
 40510  			color.toArray( colors, j ); j += 3;
 40511  
 40512  		}
 40513  
 40514  		var geometry = new BufferGeometry();
 40515  		geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 40516  		geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
 40517  
 40518  		var material = new LineBasicMaterial( { vertexColors: VertexColors } );
 40519  
 40520  		LineSegments.call( this, geometry, material );
 40521  
 40522  	}
 40523  
 40524  	GridHelper.prototype = Object.create( LineSegments.prototype );
 40525  	GridHelper.prototype.constructor = GridHelper;
 40526  
 40527  	/**
 40528  	 * @author mrdoob / http://mrdoob.com/
 40529  	 * @author Mugen87 / http://github.com/Mugen87
 40530  	 * @author Hectate / http://www.github.com/Hectate
 40531  	 */
 40532  
 40533  	function PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) {
 40534  
 40535  		radius = radius || 10;
 40536  		radials = radials || 16;
 40537  		circles = circles || 8;
 40538  		divisions = divisions || 64;
 40539  		color1 = new Color( color1 !== undefined ? color1 : 0x444444 );
 40540  		color2 = new Color( color2 !== undefined ? color2 : 0x888888 );
 40541  
 40542  		var vertices = [];
 40543  		var colors = [];
 40544  
 40545  		var x, z;
 40546  		var v, i, j, r, color;
 40547  
 40548  		// create the radials
 40549  
 40550  		for ( i = 0; i <= radials; i ++ ) {
 40551  
 40552  			v = ( i / radials ) * ( Math.PI * 2 );
 40553  
 40554  			x = Math.sin( v ) * radius;
 40555  			z = Math.cos( v ) * radius;
 40556  
 40557  			vertices.push( 0, 0, 0 );
 40558  			vertices.push( x, 0, z );
 40559  
 40560  			color = ( i & 1 ) ? color1 : color2;
 40561  
 40562  			colors.push( color.r, color.g, color.b );
 40563  			colors.push( color.r, color.g, color.b );
 40564  
 40565  		}
 40566  
 40567  		// create the circles
 40568  
 40569  		for ( i = 0; i <= circles; i ++ ) {
 40570  
 40571  			color = ( i & 1 ) ? color1 : color2;
 40572  
 40573  			r = radius - ( radius / circles * i );
 40574  
 40575  			for ( j = 0; j < divisions; j ++ ) {
 40576  
 40577  				// first vertex
 40578  
 40579  				v = ( j / divisions ) * ( Math.PI * 2 );
 40580  
 40581  				x = Math.sin( v ) * r;
 40582  				z = Math.cos( v ) * r;
 40583  
 40584  				vertices.push( x, 0, z );
 40585  				colors.push( color.r, color.g, color.b );
 40586  
 40587  				// second vertex
 40588  
 40589  				v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );
 40590  
 40591  				x = Math.sin( v ) * r;
 40592  				z = Math.cos( v ) * r;
 40593  
 40594  				vertices.push( x, 0, z );
 40595  				colors.push( color.r, color.g, color.b );
 40596  
 40597  			}
 40598  
 40599  		}
 40600  
 40601  		var geometry = new BufferGeometry();
 40602  		geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 40603  		geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
 40604  
 40605  		var material = new LineBasicMaterial( { vertexColors: VertexColors } );
 40606  
 40607  		LineSegments.call( this, geometry, material );
 40608  
 40609  	}
 40610  
 40611  	PolarGridHelper.prototype = Object.create( LineSegments.prototype );
 40612  	PolarGridHelper.prototype.constructor = PolarGridHelper;
 40613  
 40614  	/**
 40615  	 * @author mrdoob / http://mrdoob.com/
 40616  	 * @author WestLangley / http://github.com/WestLangley
 40617  	*/
 40618  
 40619  	function FaceNormalsHelper( object, size, hex, linewidth ) {
 40620  
 40621  		// FaceNormalsHelper only supports THREE.Geometry
 40622  
 40623  		this.object = object;
 40624  
 40625  		this.size = ( size !== undefined ) ? size : 1;
 40626  
 40627  		var color = ( hex !== undefined ) ? hex : 0xffff00;
 40628  
 40629  		var width = ( linewidth !== undefined ) ? linewidth : 1;
 40630  
 40631  		//
 40632  
 40633  		var nNormals = 0;
 40634  
 40635  		var objGeometry = this.object.geometry;
 40636  
 40637  		if ( objGeometry && objGeometry.isGeometry ) {
 40638  
 40639  			nNormals = objGeometry.faces.length;
 40640  
 40641  		} else {
 40642  
 40643  			console.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' );
 40644  
 40645  		}
 40646  
 40647  		//
 40648  
 40649  		var geometry = new BufferGeometry();
 40650  
 40651  		var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 );
 40652  
 40653  		geometry.addAttribute( 'position', positions );
 40654  
 40655  		LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) );
 40656  
 40657  		//
 40658  
 40659  		this.matrixAutoUpdate = false;
 40660  		this.update();
 40661  
 40662  	}
 40663  
 40664  	FaceNormalsHelper.prototype = Object.create( LineSegments.prototype );
 40665  	FaceNormalsHelper.prototype.constructor = FaceNormalsHelper;
 40666  
 40667  	FaceNormalsHelper.prototype.update = ( function () {
 40668  
 40669  		var v1 = new Vector3();
 40670  		var v2 = new Vector3();
 40671  		var normalMatrix = new Matrix3();
 40672  
 40673  		return function update() {
 40674  
 40675  			this.object.updateMatrixWorld( true );
 40676  
 40677  			normalMatrix.getNormalMatrix( this.object.matrixWorld );
 40678  
 40679  			var matrixWorld = this.object.matrixWorld;
 40680  
 40681  			var position = this.geometry.attributes.position;
 40682  
 40683  			//
 40684  
 40685  			var objGeometry = this.object.geometry;
 40686  
 40687  			var vertices = objGeometry.vertices;
 40688  
 40689  			var faces = objGeometry.faces;
 40690  
 40691  			var idx = 0;
 40692  
 40693  			for ( var i = 0, l = faces.length; i < l; i ++ ) {
 40694  
 40695  				var face = faces[ i ];
 40696  
 40697  				var normal = face.normal;
 40698  
 40699  				v1.copy( vertices[ face.a ] )
 40700  					.add( vertices[ face.b ] )
 40701  					.add( vertices[ face.c ] )
 40702  					.divideScalar( 3 )
 40703  					.applyMatrix4( matrixWorld );
 40704  
 40705  				v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );
 40706  
 40707  				position.setXYZ( idx, v1.x, v1.y, v1.z );
 40708  
 40709  				idx = idx + 1;
 40710  
 40711  				position.setXYZ( idx, v2.x, v2.y, v2.z );
 40712  
 40713  				idx = idx + 1;
 40714  
 40715  			}
 40716  
 40717  			position.needsUpdate = true;
 40718  
 40719  			return this;
 40720  
 40721  		};
 40722  
 40723  	}() );
 40724  
 40725  	/**
 40726  	 * @author alteredq / http://alteredqualia.com/
 40727  	 * @author mrdoob / http://mrdoob.com/
 40728  	 * @author WestLangley / http://github.com/WestLangley
 40729  	 */
 40730  
 40731  	function DirectionalLightHelper( light, size ) {
 40732  
 40733  		Object3D.call( this );
 40734  
 40735  		this.light = light;
 40736  		this.light.updateMatrixWorld();
 40737  
 40738  		this.matrix = light.matrixWorld;
 40739  		this.matrixAutoUpdate = false;
 40740  
 40741  		if ( size === undefined ) size = 1;
 40742  
 40743  		var geometry = new BufferGeometry();
 40744  		geometry.addAttribute( 'position', new Float32BufferAttribute( [
 40745  			- size,   size, 0,
 40746  			  size,   size, 0,
 40747  			  size, - size, 0,
 40748  			- size, - size, 0,
 40749  			- size,   size, 0
 40750  		], 3 ) );
 40751  
 40752  		var material = new LineBasicMaterial( { fog: false } );
 40753  
 40754  		this.add( new Line( geometry, material ) );
 40755  
 40756  		geometry = new BufferGeometry();
 40757  		geometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );
 40758  
 40759  		this.add( new Line( geometry, material ));
 40760  
 40761  		this.update();
 40762  
 40763  	}
 40764  
 40765  	DirectionalLightHelper.prototype = Object.create( Object3D.prototype );
 40766  	DirectionalLightHelper.prototype.constructor = DirectionalLightHelper;
 40767  
 40768  	DirectionalLightHelper.prototype.dispose = function () {
 40769  
 40770  		var lightPlane = this.children[ 0 ];
 40771  		var targetLine = this.children[ 1 ];
 40772  
 40773  		lightPlane.geometry.dispose();
 40774  		lightPlane.material.dispose();
 40775  		targetLine.geometry.dispose();
 40776  		targetLine.material.dispose();
 40777  
 40778  	};
 40779  
 40780  	DirectionalLightHelper.prototype.update = function () {
 40781  
 40782  		var v1 = new Vector3();
 40783  		var v2 = new Vector3();
 40784  		var v3 = new Vector3();
 40785  
 40786  		return function update() {
 40787  
 40788  			v1.setFromMatrixPosition( this.light.matrixWorld );
 40789  			v2.setFromMatrixPosition( this.light.target.matrixWorld );
 40790  			v3.subVectors( v2, v1 );
 40791  
 40792  			var lightPlane = this.children[ 0 ];
 40793  			var targetLine = this.children[ 1 ];
 40794  
 40795  			lightPlane.lookAt( v3 );
 40796  			lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity );
 40797  
 40798  			targetLine.lookAt( v3 );
 40799  			targetLine.scale.z = v3.length();
 40800  
 40801  		};
 40802  
 40803  	}();
 40804  
 40805  	/**
 40806  	 * @author alteredq / http://alteredqualia.com/
 40807  	 * @author Mugen87 / https://github.com/Mugen87
 40808  	 *
 40809  	 *	- shows frustum, line of sight and up of the camera
 40810  	 *	- suitable for fast updates
 40811  	 * 	- based on frustum visualization in lightgl.js shadowmap example
 40812  	 *		http://evanw.github.com/lightgl.js/tests/shadowmap.html
 40813  	 */
 40814  
 40815  	function CameraHelper( camera ) {
 40816  
 40817  		var geometry = new BufferGeometry();
 40818  		var material = new LineBasicMaterial( { color: 0xffffff, vertexColors: FaceColors } );
 40819  
 40820  		var vertices = [];
 40821  		var colors = [];
 40822  
 40823  		var pointMap = {};
 40824  
 40825  		// colors
 40826  
 40827  		var colorFrustum = new Color( 0xffaa00 );
 40828  		var colorCone = new Color( 0xff0000 );
 40829  		var colorUp = new Color( 0x00aaff );
 40830  		var colorTarget = new Color( 0xffffff );
 40831  		var colorCross = new Color( 0x333333 );
 40832  
 40833  		// near
 40834  
 40835  		addLine( "n1", "n2", colorFrustum );
 40836  		addLine( "n2", "n4", colorFrustum );
 40837  		addLine( "n4", "n3", colorFrustum );
 40838  		addLine( "n3", "n1", colorFrustum );
 40839  
 40840  		// far
 40841  
 40842  		addLine( "f1", "f2", colorFrustum );
 40843  		addLine( "f2", "f4", colorFrustum );
 40844  		addLine( "f4", "f3", colorFrustum );
 40845  		addLine( "f3", "f1", colorFrustum );
 40846  
 40847  		// sides
 40848  
 40849  		addLine( "n1", "f1", colorFrustum );
 40850  		addLine( "n2", "f2", colorFrustum );
 40851  		addLine( "n3", "f3", colorFrustum );
 40852  		addLine( "n4", "f4", colorFrustum );
 40853  
 40854  		// cone
 40855  
 40856  		addLine( "p", "n1", colorCone );
 40857  		addLine( "p", "n2", colorCone );
 40858  		addLine( "p", "n3", colorCone );
 40859  		addLine( "p", "n4", colorCone );
 40860  
 40861  		// up
 40862  
 40863  		addLine( "u1", "u2", colorUp );
 40864  		addLine( "u2", "u3", colorUp );
 40865  		addLine( "u3", "u1", colorUp );
 40866  
 40867  		// target
 40868  
 40869  		addLine( "c", "t", colorTarget );
 40870  		addLine( "p", "c", colorCross );
 40871  
 40872  		// cross
 40873  
 40874  		addLine( "cn1", "cn2", colorCross );
 40875  		addLine( "cn3", "cn4", colorCross );
 40876  
 40877  		addLine( "cf1", "cf2", colorCross );
 40878  		addLine( "cf3", "cf4", colorCross );
 40879  
 40880  		function addLine( a, b, color ) {
 40881  
 40882  			addPoint( a, color );
 40883  			addPoint( b, color );
 40884  
 40885  		}
 40886  
 40887  		function addPoint( id, color ) {
 40888  
 40889  			vertices.push( 0, 0, 0 );
 40890  			colors.push( color.r, color.g, color.b );
 40891  
 40892  			if ( pointMap[ id ] === undefined ) {
 40893  
 40894  				pointMap[ id ] = [];
 40895  
 40896  			}
 40897  
 40898  			pointMap[ id ].push( ( vertices.length / 3 ) - 1 );
 40899  
 40900  		}
 40901  
 40902  		geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 40903  		geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
 40904  
 40905  		LineSegments.call( this, geometry, material );
 40906  
 40907  		this.camera = camera;
 40908  		if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();
 40909  
 40910  		this.matrix = camera.matrixWorld;
 40911  		this.matrixAutoUpdate = false;
 40912  
 40913  		this.pointMap = pointMap;
 40914  
 40915  		this.update();
 40916  
 40917  	}
 40918  
 40919  	CameraHelper.prototype = Object.create( LineSegments.prototype );
 40920  	CameraHelper.prototype.constructor = CameraHelper;
 40921  
 40922  	CameraHelper.prototype.update = function () {
 40923  
 40924  		var geometry, pointMap;
 40925  
 40926  		var vector = new Vector3();
 40927  		var camera = new Camera();
 40928  
 40929  		function setPoint( point, x, y, z ) {
 40930  
 40931  			vector.set( x, y, z ).unproject( camera );
 40932  
 40933  			var points = pointMap[ point ];
 40934  
 40935  			if ( points !== undefined ) {
 40936  
 40937  				var position = geometry.getAttribute( 'position' );
 40938  
 40939  				for ( var i = 0, l = points.length; i < l; i ++ ) {
 40940  
 40941  					position.setXYZ( points[ i ], vector.x, vector.y, vector.z );
 40942  
 40943  				}
 40944  
 40945  			}
 40946  
 40947  		}
 40948  
 40949  		return function update() {
 40950  
 40951  			geometry = this.geometry;
 40952  			pointMap = this.pointMap;
 40953  
 40954  			var w = 1, h = 1;
 40955  
 40956  			// we need just camera projection matrix
 40957  			// world matrix must be identity
 40958  
 40959  			camera.projectionMatrix.copy( this.camera.projectionMatrix );
 40960  
 40961  			// center / target
 40962  
 40963  			setPoint( "c", 0, 0, - 1 );
 40964  			setPoint( "t", 0, 0,  1 );
 40965  
 40966  			// near
 40967  
 40968  			setPoint( "n1", - w, - h, - 1 );
 40969  			setPoint( "n2",   w, - h, - 1 );
 40970  			setPoint( "n3", - w,   h, - 1 );
 40971  			setPoint( "n4",   w,   h, - 1 );
 40972  
 40973  			// far
 40974  
 40975  			setPoint( "f1", - w, - h, 1 );
 40976  			setPoint( "f2",   w, - h, 1 );
 40977  			setPoint( "f3", - w,   h, 1 );
 40978  			setPoint( "f4",   w,   h, 1 );
 40979  
 40980  			// up
 40981  
 40982  			setPoint( "u1",   w * 0.7, h * 1.1, - 1 );
 40983  			setPoint( "u2", - w * 0.7, h * 1.1, - 1 );
 40984  			setPoint( "u3",         0, h * 2,   - 1 );
 40985  
 40986  			// cross
 40987  
 40988  			setPoint( "cf1", - w,   0, 1 );
 40989  			setPoint( "cf2",   w,   0, 1 );
 40990  			setPoint( "cf3",   0, - h, 1 );
 40991  			setPoint( "cf4",   0,   h, 1 );
 40992  
 40993  			setPoint( "cn1", - w,   0, - 1 );
 40994  			setPoint( "cn2",   w,   0, - 1 );
 40995  			setPoint( "cn3",   0, - h, - 1 );
 40996  			setPoint( "cn4",   0,   h, - 1 );
 40997  
 40998  			geometry.getAttribute( 'position' ).needsUpdate = true;
 40999  
 41000  		};
 41001  
 41002  	}();
 41003  
 41004  	/**
 41005  	 * @author mrdoob / http://mrdoob.com/
 41006  	 */
 41007  
 41008  	function BoxHelper( object, color ) {
 41009  
 41010  		if ( color === undefined ) color = 0xffff00;
 41011  
 41012  		var indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
 41013  		var positions = new Float32Array( 8 * 3 );
 41014  
 41015  		var geometry = new BufferGeometry();
 41016  		geometry.setIndex( new BufferAttribute( indices, 1 ) );
 41017  		geometry.addAttribute( 'position', new BufferAttribute( positions, 3 ) );
 41018  
 41019  		LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) );
 41020  
 41021  		if ( object !== undefined ) {
 41022  
 41023  			this.update( object );
 41024  
 41025  		}
 41026  
 41027  	}
 41028  
 41029  	BoxHelper.prototype = Object.create( LineSegments.prototype );
 41030  	BoxHelper.prototype.constructor = BoxHelper;
 41031  
 41032  	BoxHelper.prototype.update = ( function () {
 41033  
 41034  		var box = new Box3();
 41035  
 41036  		return function update( object ) {
 41037  
 41038  			if ( object && object.isBox3 ) {
 41039  
 41040  				box.copy( object );
 41041  
 41042  			} else {
 41043  
 41044  				box.setFromObject( object );
 41045  
 41046  			}
 41047  
 41048  			if ( box.isEmpty() ) return;
 41049  
 41050  			var min = box.min;
 41051  			var max = box.max;
 41052  
 41053  			/*
 41054  			  5____4
 41055  			1/___0/|
 41056  			| 6__|_7
 41057  			2/___3/
 41058  
 41059  			0: max.x, max.y, max.z
 41060  			1: min.x, max.y, max.z
 41061  			2: min.x, min.y, max.z
 41062  			3: max.x, min.y, max.z
 41063  			4: max.x, max.y, min.z
 41064  			5: min.x, max.y, min.z
 41065  			6: min.x, min.y, min.z
 41066  			7: max.x, min.y, min.z
 41067  			*/
 41068  
 41069  			var position = this.geometry.attributes.position;
 41070  			var array = position.array;
 41071  
 41072  			array[  0 ] = max.x; array[  1 ] = max.y; array[  2 ] = max.z;
 41073  			array[  3 ] = min.x; array[  4 ] = max.y; array[  5 ] = max.z;
 41074  			array[  6 ] = min.x; array[  7 ] = min.y; array[  8 ] = max.z;
 41075  			array[  9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;
 41076  			array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;
 41077  			array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;
 41078  			array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;
 41079  			array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;
 41080  
 41081  			position.needsUpdate = true;
 41082  
 41083  			this.geometry.computeBoundingSphere();
 41084  
 41085  		};
 41086  
 41087  	} )();
 41088  
 41089  	/**
 41090  	 * @author WestLangley / http://github.com/WestLangley
 41091  	 * @author zz85 / http://github.com/zz85
 41092  	 * @author bhouston / http://clara.io
 41093  	 *
 41094  	 * Creates an arrow for visualizing directions
 41095  	 *
 41096  	 * Parameters:
 41097  	 *  dir - Vector3
 41098  	 *  origin - Vector3
 41099  	 *  length - Number
 41100  	 *  color - color in hex value
 41101  	 *  headLength - Number
 41102  	 *  headWidth - Number
 41103  	 */
 41104  
 41105  	var lineGeometry;
 41106  	var coneGeometry;
 41107  
 41108  	function ArrowHelper( dir, origin, length, color, headLength, headWidth ) {
 41109  
 41110  		// dir is assumed to be normalized
 41111  
 41112  		Object3D.call( this );
 41113  
 41114  		if ( color === undefined ) color = 0xffff00;
 41115  		if ( length === undefined ) length = 1;
 41116  		if ( headLength === undefined ) headLength = 0.2 * length;
 41117  		if ( headWidth === undefined ) headWidth = 0.2 * headLength;
 41118  
 41119  		if ( lineGeometry === undefined ) {
 41120  
 41121  			lineGeometry = new BufferGeometry();
 41122  			lineGeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
 41123  
 41124  			coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );
 41125  			coneGeometry.translate( 0, - 0.5, 0 );
 41126  
 41127  		}
 41128  
 41129  		this.position.copy( origin );
 41130  
 41131  		this.line = new Line( lineGeometry, new LineBasicMaterial( { color: color } ) );
 41132  		this.line.matrixAutoUpdate = false;
 41133  		this.add( this.line );
 41134  
 41135  		this.cone = new Mesh( coneGeometry, new MeshBasicMaterial( { color: color } ) );
 41136  		this.cone.matrixAutoUpdate = false;
 41137  		this.add( this.cone );
 41138  
 41139  		this.setDirection( dir );
 41140  		this.setLength( length, headLength, headWidth );
 41141  
 41142  	}
 41143  
 41144  	ArrowHelper.prototype = Object.create( Object3D.prototype );
 41145  	ArrowHelper.prototype.constructor = ArrowHelper;
 41146  
 41147  	ArrowHelper.prototype.setDirection = ( function () {
 41148  
 41149  		var axis = new Vector3();
 41150  		var radians;
 41151  
 41152  		return function setDirection( dir ) {
 41153  
 41154  			// dir is assumed to be normalized
 41155  
 41156  			if ( dir.y > 0.99999 ) {
 41157  
 41158  				this.quaternion.set( 0, 0, 0, 1 );
 41159  
 41160  			} else if ( dir.y < - 0.99999 ) {
 41161  
 41162  				this.quaternion.set( 1, 0, 0, 0 );
 41163  
 41164  			} else {
 41165  
 41166  				axis.set( dir.z, 0, - dir.x ).normalize();
 41167  
 41168  				radians = Math.acos( dir.y );
 41169  
 41170  				this.quaternion.setFromAxisAngle( axis, radians );
 41171  
 41172  			}
 41173  
 41174  		};
 41175  
 41176  	}() );
 41177  
 41178  	ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) {
 41179  
 41180  		if ( headLength === undefined ) headLength = 0.2 * length;
 41181  		if ( headWidth === undefined ) headWidth = 0.2 * headLength;
 41182  
 41183  		this.line.scale.set( 1, Math.max( 0, length - headLength ), 1 );
 41184  		this.line.updateMatrix();
 41185  
 41186  		this.cone.scale.set( headWidth, headLength, headWidth );
 41187  		this.cone.position.y = length;
 41188  		this.cone.updateMatrix();
 41189  
 41190  	};
 41191  
 41192  	ArrowHelper.prototype.setColor = function ( color ) {
 41193  
 41194  		this.line.material.color.copy( color );
 41195  		this.cone.material.color.copy( color );
 41196  
 41197  	};
 41198  
 41199  	/**
 41200  	 * @author sroucheray / http://sroucheray.org/
 41201  	 * @author mrdoob / http://mrdoob.com/
 41202  	 */
 41203  
 41204  	function AxisHelper( size ) {
 41205  
 41206  		size = size || 1;
 41207  
 41208  		var vertices = [
 41209  			0, 0, 0,  size, 0, 0,
 41210  			0, 0, 0,  0, size, 0,
 41211  			0, 0, 0,  0, 0, size
 41212  		];
 41213  
 41214  		var colors = [
 41215  			1, 0, 0,  1, 0.6, 0,
 41216  			0, 1, 0,  0.6, 1, 0,
 41217  			0, 0, 1,  0, 0.6, 1
 41218  		];
 41219  
 41220  		var geometry = new BufferGeometry();
 41221  		geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 41222  		geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
 41223  
 41224  		var material = new LineBasicMaterial( { vertexColors: VertexColors } );
 41225  
 41226  		LineSegments.call( this, geometry, material );
 41227  
 41228  	}
 41229  
 41230  	AxisHelper.prototype = Object.create( LineSegments.prototype );
 41231  	AxisHelper.prototype.constructor = AxisHelper;
 41232  
 41233  	/**
 41234  	 * @author zz85 https://github.com/zz85
 41235  	 *
 41236  	 * Centripetal CatmullRom Curve - which is useful for avoiding
 41237  	 * cusps and self-intersections in non-uniform catmull rom curves.
 41238  	 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
 41239  	 *
 41240  	 * curve.type accepts centripetal(default), chordal and catmullrom
 41241  	 * curve.tension is used for catmullrom which defaults to 0.5
 41242  	 */
 41243  
 41244  
 41245  	/*
 41246  	Based on an optimized c++ solution in
 41247  	 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
 41248  	 - http://ideone.com/NoEbVM
 41249  
 41250  	This CubicPoly class could be used for reusing some variables and calculations,
 41251  	but for three.js curve use, it could be possible inlined and flatten into a single function call
 41252  	which can be placed in CurveUtils.
 41253  	*/
 41254  
 41255  	function CubicPoly() {
 41256  
 41257  		var c0 = 0, c1 = 0, c2 = 0, c3 = 0;
 41258  
 41259  		/*
 41260  		 * Compute coefficients for a cubic polynomial
 41261  		 *   p(s) = c0 + c1*s + c2*s^2 + c3*s^3
 41262  		 * such that
 41263  		 *   p(0) = x0, p(1) = x1
 41264  		 *  and
 41265  		 *   p'(0) = t0, p'(1) = t1.
 41266  		 */
 41267  		function init( x0, x1, t0, t1 ) {
 41268  
 41269  			c0 = x0;
 41270  			c1 = t0;
 41271  			c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
 41272  			c3 = 2 * x0 - 2 * x1 + t0 + t1;
 41273  
 41274  		}
 41275  
 41276  		return {
 41277  
 41278  			initCatmullRom: function ( x0, x1, x2, x3, tension ) {
 41279  
 41280  				init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );
 41281  
 41282  			},
 41283  
 41284  			initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {
 41285  
 41286  				// compute tangents when parameterized in [t1,t2]
 41287  				var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
 41288  				var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;
 41289  
 41290  				// rescale tangents for parametrization in [0,1]
 41291  				t1 *= dt1;
 41292  				t2 *= dt1;
 41293  
 41294  				init( x1, x2, t1, t2 );
 41295  
 41296  			},
 41297  
 41298  			calc: function ( t ) {
 41299  
 41300  				var t2 = t * t;
 41301  				var t3 = t2 * t;
 41302  				return c0 + c1 * t + c2 * t2 + c3 * t3;
 41303  
 41304  			}
 41305  
 41306  		};
 41307  
 41308  	}
 41309  
 41310  	//
 41311  
 41312  	var tmp = new Vector3();
 41313  	var px = new CubicPoly();
 41314  	var py = new CubicPoly();
 41315  	var pz = new CubicPoly();
 41316  
 41317  	function CatmullRomCurve3( p /* array of Vector3 */ ) {
 41318  
 41319  		this.points = p || [];
 41320  		this.closed = false;
 41321  
 41322  	}
 41323  
 41324  	CatmullRomCurve3.prototype = Object.create( Curve.prototype );
 41325  	CatmullRomCurve3.prototype.constructor = CatmullRomCurve3;
 41326  
 41327  	CatmullRomCurve3.prototype.getPoint = function ( t ) {
 41328  
 41329  		var points = this.points;
 41330  		var l = points.length;
 41331  
 41332  		if ( l < 2 ) console.log( 'duh, you need at least 2 points' );
 41333  
 41334  		var point = ( l - ( this.closed ? 0 : 1 ) ) * t;
 41335  		var intPoint = Math.floor( point );
 41336  		var weight = point - intPoint;
 41337  
 41338  		if ( this.closed ) {
 41339  
 41340  			intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length;
 41341  
 41342  		} else if ( weight === 0 && intPoint === l - 1 ) {
 41343  
 41344  			intPoint = l - 2;
 41345  			weight = 1;
 41346  
 41347  		}
 41348  
 41349  		var p0, p1, p2, p3; // 4 points
 41350  
 41351  		if ( this.closed || intPoint > 0 ) {
 41352  
 41353  			p0 = points[ ( intPoint - 1 ) % l ];
 41354  
 41355  		} else {
 41356  
 41357  			// extrapolate first point
 41358  			tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
 41359  			p0 = tmp;
 41360  
 41361  		}
 41362  
 41363  		p1 = points[ intPoint % l ];
 41364  		p2 = points[ ( intPoint + 1 ) % l ];
 41365  
 41366  		if ( this.closed || intPoint + 2 < l ) {
 41367  
 41368  			p3 = points[ ( intPoint + 2 ) % l ];
 41369  
 41370  		} else {
 41371  
 41372  			// extrapolate last point
 41373  			tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
 41374  			p3 = tmp;
 41375  
 41376  		}
 41377  
 41378  		if ( this.type === undefined || this.type === 'centripetal' || this.type === 'chordal' ) {
 41379  
 41380  			// init Centripetal / Chordal Catmull-Rom
 41381  			var pow = this.type === 'chordal' ? 0.5 : 0.25;
 41382  			var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
 41383  			var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
 41384  			var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
 41385  
 41386  			// safety check for repeated points
 41387  			if ( dt1 < 1e-4 ) dt1 = 1.0;
 41388  			if ( dt0 < 1e-4 ) dt0 = dt1;
 41389  			if ( dt2 < 1e-4 ) dt2 = dt1;
 41390  
 41391  			px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
 41392  			py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
 41393  			pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
 41394  
 41395  		} else if ( this.type === 'catmullrom' ) {
 41396  
 41397  			var tension = this.tension !== undefined ? this.tension : 0.5;
 41398  			px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, tension );
 41399  			py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, tension );
 41400  			pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, tension );
 41401  
 41402  		}
 41403  
 41404  		return new Vector3( px.calc( weight ), py.calc( weight ), pz.calc( weight ) );
 41405  
 41406  	};
 41407  
 41408  	function CubicBezierCurve3( v0, v1, v2, v3 ) {
 41409  
 41410  		this.v0 = v0;
 41411  		this.v1 = v1;
 41412  		this.v2 = v2;
 41413  		this.v3 = v3;
 41414  
 41415  	}
 41416  
 41417  	CubicBezierCurve3.prototype = Object.create( Curve.prototype );
 41418  	CubicBezierCurve3.prototype.constructor = CubicBezierCurve3;
 41419  
 41420  	CubicBezierCurve3.prototype.getPoint = function ( t ) {
 41421  
 41422  		var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
 41423  
 41424  		return new Vector3(
 41425  			CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
 41426  			CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
 41427  			CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
 41428  		);
 41429  
 41430  	};
 41431  
 41432  	function QuadraticBezierCurve3( v0, v1, v2 ) {
 41433  
 41434  		this.v0 = v0;
 41435  		this.v1 = v1;
 41436  		this.v2 = v2;
 41437  
 41438  	}
 41439  
 41440  	QuadraticBezierCurve3.prototype = Object.create( Curve.prototype );
 41441  	QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3;
 41442  
 41443  	QuadraticBezierCurve3.prototype.getPoint = function ( t ) {
 41444  
 41445  		var v0 = this.v0, v1 = this.v1, v2 = this.v2;
 41446  
 41447  		return new Vector3(
 41448  			QuadraticBezier( t, v0.x, v1.x, v2.x ),
 41449  			QuadraticBezier( t, v0.y, v1.y, v2.y ),
 41450  			QuadraticBezier( t, v0.z, v1.z, v2.z )
 41451  		);
 41452  
 41453  	};
 41454  
 41455  	function LineCurve3( v1, v2 ) {
 41456  
 41457  		this.v1 = v1;
 41458  		this.v2 = v2;
 41459  
 41460  	}
 41461  
 41462  	LineCurve3.prototype = Object.create( Curve.prototype );
 41463  	LineCurve3.prototype.constructor = LineCurve3;
 41464  
 41465  	LineCurve3.prototype.getPoint = function ( t ) {
 41466  
 41467  		if ( t === 1 ) {
 41468  
 41469  			return this.v2.clone();
 41470  
 41471  		}
 41472  
 41473  		var vector = new Vector3();
 41474  
 41475  		vector.subVectors( this.v2, this.v1 ); // diff
 41476  		vector.multiplyScalar( t );
 41477  		vector.add( this.v1 );
 41478  
 41479  		return vector;
 41480  
 41481  	};
 41482  
 41483  	function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
 41484  
 41485  		EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
 41486  
 41487  	}
 41488  
 41489  	ArcCurve.prototype = Object.create( EllipseCurve.prototype );
 41490  	ArcCurve.prototype.constructor = ArcCurve;
 41491  
 41492  	/**
 41493  	 * @author alteredq / http://alteredqualia.com/
 41494  	 */
 41495  
 41496  	var SceneUtils = {
 41497  
 41498  		createMultiMaterialObject: function ( geometry, materials ) {
 41499  
 41500  			var group = new Group();
 41501  
 41502  			for ( var i = 0, l = materials.length; i < l; i ++ ) {
 41503  
 41504  				group.add( new Mesh( geometry, materials[ i ] ) );
 41505  
 41506  			}
 41507  
 41508  			return group;
 41509  
 41510  		},
 41511  
 41512  		detach: function ( child, parent, scene ) {
 41513  
 41514  			child.applyMatrix( parent.matrixWorld );
 41515  			parent.remove( child );
 41516  			scene.add( child );
 41517  
 41518  		},
 41519  
 41520  		attach: function ( child, scene, parent ) {
 41521  
 41522  			var matrixWorldInverse = new Matrix4();
 41523  			matrixWorldInverse.getInverse( parent.matrixWorld );
 41524  			child.applyMatrix( matrixWorldInverse );
 41525  
 41526  			scene.remove( child );
 41527  			parent.add( child );
 41528  
 41529  		}
 41530  
 41531  	};
 41532  
 41533  	/**
 41534  	 * @author mrdoob / http://mrdoob.com/
 41535  	 */
 41536  
 41537  	function Face4( a, b, c, d, normal, color, materialIndex ) {
 41538  
 41539  		console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' );
 41540  		return new Face3( a, b, c, normal, color, materialIndex );
 41541  
 41542  	}
 41543  
 41544  	var LineStrip = 0;
 41545  
 41546  	var LinePieces = 1;
 41547  
 41548  	function MeshFaceMaterial( materials ) {
 41549  
 41550  		console.warn( 'THREE.MeshFaceMaterial has been renamed to THREE.MultiMaterial.' );
 41551  		return new MultiMaterial( materials );
 41552  
 41553  	}
 41554  
 41555  	function PointCloud( geometry, material ) {
 41556  
 41557  		console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' );
 41558  		return new Points( geometry, material );
 41559  
 41560  	}
 41561  
 41562  	function Particle( material ) {
 41563  
 41564  		console.warn( 'THREE.Particle has been renamed to THREE.Sprite.' );
 41565  		return new Sprite( material );
 41566  
 41567  	}
 41568  
 41569  	function ParticleSystem( geometry, material ) {
 41570  
 41571  		console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' );
 41572  		return new Points( geometry, material );
 41573  
 41574  	}
 41575  
 41576  	function PointCloudMaterial( parameters ) {
 41577  
 41578  		console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' );
 41579  		return new PointsMaterial( parameters );
 41580  
 41581  	}
 41582  
 41583  	function ParticleBasicMaterial( parameters ) {
 41584  
 41585  		console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' );
 41586  		return new PointsMaterial( parameters );
 41587  
 41588  	}
 41589  
 41590  	function ParticleSystemMaterial( parameters ) {
 41591  
 41592  		console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' );
 41593  		return new PointsMaterial( parameters );
 41594  
 41595  	}
 41596  
 41597  	function Vertex( x, y, z ) {
 41598  
 41599  		console.warn( 'THREE.Vertex has been removed. Use THREE.Vector3 instead.' );
 41600  		return new Vector3( x, y, z );
 41601  
 41602  	}
 41603  
 41604  	//
 41605  
 41606  	function DynamicBufferAttribute( array, itemSize ) {
 41607  
 41608  		console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.' );
 41609  		return new BufferAttribute( array, itemSize ).setDynamic( true );
 41610  
 41611  	}
 41612  
 41613  	function Int8Attribute( array, itemSize ) {
 41614  
 41615  		console.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' );
 41616  		return new Int8BufferAttribute( array, itemSize );
 41617  
 41618  	}
 41619  
 41620  	function Uint8Attribute( array, itemSize ) {
 41621  
 41622  		console.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' );
 41623  		return new Uint8BufferAttribute( array, itemSize );
 41624  
 41625  	}
 41626  
 41627  	function Uint8ClampedAttribute( array, itemSize ) {
 41628  
 41629  		console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.' );
 41630  		return new Uint8ClampedBufferAttribute( array, itemSize );
 41631  
 41632  	}
 41633  
 41634  	function Int16Attribute( array, itemSize ) {
 41635  
 41636  		console.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' );
 41637  		return new Int16BufferAttribute( array, itemSize );
 41638  
 41639  	}
 41640  
 41641  	function Uint16Attribute( array, itemSize ) {
 41642  
 41643  		console.warn( 'THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.' );
 41644  		return new Uint16BufferAttribute( array, itemSize );
 41645  
 41646  	}
 41647  
 41648  	function Int32Attribute( array, itemSize ) {
 41649  
 41650  		console.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' );
 41651  		return new Int32BufferAttribute( array, itemSize );
 41652  
 41653  	}
 41654  
 41655  	function Uint32Attribute( array, itemSize ) {
 41656  
 41657  		console.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' );
 41658  		return new Uint32BufferAttribute( array, itemSize );
 41659  
 41660  	}
 41661  
 41662  	function Float32Attribute( array, itemSize ) {
 41663  
 41664  		console.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' );
 41665  		return new Float32BufferAttribute( array, itemSize );
 41666  
 41667  	}
 41668  
 41669  	function Float64Attribute( array, itemSize ) {
 41670  
 41671  		console.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' );
 41672  		return new Float64BufferAttribute( array, itemSize );
 41673  
 41674  	}
 41675  
 41676  	//
 41677  
 41678  	Curve.create = function ( construct, getPoint ) {
 41679  
 41680  		console.log( 'THREE.Curve.create() has been deprecated' );
 41681  
 41682  		construct.prototype = Object.create( Curve.prototype );
 41683  		construct.prototype.constructor = construct;
 41684  		construct.prototype.getPoint = getPoint;
 41685  
 41686  		return construct;
 41687  
 41688  	};
 41689  
 41690  	//
 41691  
 41692  	function ClosedSplineCurve3( points ) {
 41693  
 41694  		console.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );
 41695  
 41696  		CatmullRomCurve3.call( this, points );
 41697  		this.type = 'catmullrom';
 41698  		this.closed = true;
 41699  
 41700  	}
 41701  
 41702  	ClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );
 41703  
 41704  	//
 41705  
 41706  	function SplineCurve3( points ) {
 41707  
 41708  		console.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );
 41709  
 41710  		CatmullRomCurve3.call( this, points );
 41711  		this.type = 'catmullrom';
 41712  
 41713  	}
 41714  
 41715  	SplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );
 41716  
 41717  	//
 41718  
 41719  	function Spline( points ) {
 41720  
 41721  		console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' );
 41722  
 41723  		CatmullRomCurve3.call( this, points );
 41724  		this.type = 'catmullrom';
 41725  
 41726  	}
 41727  
 41728  	Spline.prototype = Object.create( CatmullRomCurve3.prototype );
 41729  
 41730  	Object.assign( Spline.prototype, {
 41731  
 41732  		initFromArray: function ( a ) {
 41733  
 41734  			console.error( 'THREE.Spline: .initFromArray() has been removed.' );
 41735  
 41736  		},
 41737  		getControlPointsArray: function ( optionalTarget ) {
 41738  
 41739  			console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' );
 41740  
 41741  		},
 41742  		reparametrizeByArcLength: function ( samplingCoef ) {
 41743  
 41744  			console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' );
 41745  
 41746  		}
 41747  
 41748  	} );
 41749  
 41750  	//
 41751  	function BoundingBoxHelper( object, color ) {
 41752  
 41753  		console.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' );
 41754  		return new BoxHelper( object, color );
 41755  
 41756  	}
 41757  
 41758  	function EdgesHelper( object, hex ) {
 41759  
 41760  		console.warn( 'THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead.' );
 41761  		return new LineSegments( new EdgesGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );
 41762  
 41763  	}
 41764  
 41765  	GridHelper.prototype.setColors = function () {
 41766  
 41767  		console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' );
 41768  
 41769  	};
 41770  
 41771  	function WireframeHelper( object, hex ) {
 41772  
 41773  		console.warn( 'THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead.' );
 41774  		return new LineSegments( new WireframeGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );
 41775  
 41776  	}
 41777  
 41778  	//
 41779  
 41780  	function XHRLoader( manager ) {
 41781  
 41782  		console.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' );
 41783  		return new FileLoader( manager );
 41784  
 41785  	}
 41786  
 41787  	function BinaryTextureLoader( manager ) {
 41788  
 41789  		console.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' );
 41790  		return new DataTextureLoader( manager );
 41791  
 41792  	}
 41793  
 41794  	//
 41795  
 41796  	Object.assign( Box2.prototype, {
 41797  
 41798  		center: function ( optionalTarget ) {
 41799  
 41800  			console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' );
 41801  			return this.getCenter( optionalTarget );
 41802  
 41803  		},
 41804  		empty: function () {
 41805  
 41806  			console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' );
 41807  			return this.isEmpty();
 41808  
 41809  		},
 41810  		isIntersectionBox: function ( box ) {
 41811  
 41812  			console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' );
 41813  			return this.intersectsBox( box );
 41814  
 41815  		},
 41816  		size: function ( optionalTarget ) {
 41817  
 41818  			console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' );
 41819  			return this.getSize( optionalTarget );
 41820  
 41821  		}
 41822  	} );
 41823  
 41824  	Object.assign( Box3.prototype, {
 41825  
 41826  		center: function ( optionalTarget ) {
 41827  
 41828  			console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' );
 41829  			return this.getCenter( optionalTarget );
 41830  
 41831  		},
 41832  		empty: function () {
 41833  
 41834  			console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' );
 41835  			return this.isEmpty();
 41836  
 41837  		},
 41838  		isIntersectionBox: function ( box ) {
 41839  
 41840  			console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' );
 41841  			return this.intersectsBox( box );
 41842  
 41843  		},
 41844  		isIntersectionSphere: function ( sphere ) {
 41845  
 41846  			console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
 41847  			return this.intersectsSphere( sphere );
 41848  
 41849  		},
 41850  		size: function ( optionalTarget ) {
 41851  
 41852  			console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' );
 41853  			return this.getSize( optionalTarget );
 41854  
 41855  		}
 41856  	} );
 41857  
 41858  	Line3.prototype.center = function ( optionalTarget ) {
 41859  
 41860  		console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' );
 41861  		return this.getCenter( optionalTarget );
 41862  
 41863  	};
 41864  
 41865  	_Math.random16 = function () {
 41866  
 41867  		console.warn( 'THREE.Math.random16() has been deprecated. Use Math.random() instead.' );
 41868  		return Math.random();
 41869  
 41870  	};
 41871  
 41872  	Object.assign( Matrix3.prototype, {
 41873  
 41874  		flattenToArrayOffset: function ( array, offset ) {
 41875  
 41876  			console.warn( "THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." );
 41877  			return this.toArray( array, offset );
 41878  
 41879  		},
 41880  		multiplyVector3: function ( vector ) {
 41881  
 41882  			console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );
 41883  			return vector.applyMatrix3( this );
 41884  
 41885  		},
 41886  		multiplyVector3Array: function ( a ) {
 41887  
 41888  			console.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' );
 41889  			return this.applyToVector3Array( a );
 41890  
 41891  		},
 41892  		applyToBuffer: function( buffer, offset, length ) {
 41893  
 41894  			console.warn( 'THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' );
 41895  			return this.applyToBufferAttribute( buffer );
 41896  
 41897  		},
 41898  		applyToVector3Array: function( array, offset, length ) {
 41899  
 41900  			console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' );
 41901  
 41902  		}
 41903  
 41904  	} );
 41905  
 41906  	Object.assign( Matrix4.prototype, {
 41907  
 41908  		extractPosition: function ( m ) {
 41909  
 41910  			console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' );
 41911  			return this.copyPosition( m );
 41912  
 41913  		},
 41914  		flattenToArrayOffset: function ( array, offset ) {
 41915  
 41916  			console.warn( "THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." );
 41917  			return this.toArray( array, offset );
 41918  
 41919  		},
 41920  		getPosition: function () {
 41921  
 41922  			var v1;
 41923  
 41924  			return function getPosition() {
 41925  
 41926  				if ( v1 === undefined ) v1 = new Vector3();
 41927  				console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );
 41928  				return v1.setFromMatrixColumn( this, 3 );
 41929  
 41930  			};
 41931  
 41932  		}(),
 41933  		setRotationFromQuaternion: function ( q ) {
 41934  
 41935  			console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );
 41936  			return this.makeRotationFromQuaternion( q );
 41937  
 41938  		},
 41939  		multiplyVector3: function ( vector ) {
 41940  
 41941  			console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
 41942  			return vector.applyMatrix4( this );
 41943  
 41944  		},
 41945  		multiplyVector4: function ( vector ) {
 41946  
 41947  			console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
 41948  			return vector.applyMatrix4( this );
 41949  
 41950  		},
 41951  		multiplyVector3Array: function ( a ) {
 41952  
 41953  			console.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' );
 41954  			return this.applyToVector3Array( a );
 41955  
 41956  		},
 41957  		rotateAxis: function ( v ) {
 41958  
 41959  			console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );
 41960  			v.transformDirection( this );
 41961  
 41962  		},
 41963  		crossVector: function ( vector ) {
 41964  
 41965  			console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );
 41966  			return vector.applyMatrix4( this );
 41967  
 41968  		},
 41969  		translate: function () {
 41970  
 41971  			console.error( 'THREE.Matrix4: .translate() has been removed.' );
 41972  
 41973  		},
 41974  		rotateX: function () {
 41975  
 41976  			console.error( 'THREE.Matrix4: .rotateX() has been removed.' );
 41977  
 41978  		},
 41979  		rotateY: function () {
 41980  
 41981  			console.error( 'THREE.Matrix4: .rotateY() has been removed.' );
 41982  
 41983  		},
 41984  		rotateZ: function () {
 41985  
 41986  			console.error( 'THREE.Matrix4: .rotateZ() has been removed.' );
 41987  
 41988  		},
 41989  		rotateByAxis: function () {
 41990  
 41991  			console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' );
 41992  
 41993  		},
 41994  		applyToBuffer: function( buffer, offset, length ) {
 41995  
 41996  			console.warn( 'THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' );
 41997  			return this.applyToBufferAttribute( buffer );
 41998  
 41999  		},
 42000  		applyToVector3Array: function( array, offset, length ) {
 42001  
 42002  			console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' );
 42003  
 42004  		},
 42005  		makeFrustum: function( left, right, bottom, top, near, far ) {
 42006  
 42007  			console.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' );
 42008  			return this.makePerspective( left, right, top, bottom, near, far );
 42009  
 42010  		}
 42011  
 42012  	} );
 42013  
 42014  	Plane.prototype.isIntersectionLine = function ( line ) {
 42015  
 42016  		console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' );
 42017  		return this.intersectsLine( line );
 42018  
 42019  	};
 42020  
 42021  	Quaternion.prototype.multiplyVector3 = function ( vector ) {
 42022  
 42023  		console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
 42024  		return vector.applyQuaternion( this );
 42025  
 42026  	};
 42027  
 42028  	Object.assign( Ray.prototype, {
 42029  
 42030  		isIntersectionBox: function ( box ) {
 42031  
 42032  			console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' );
 42033  			return this.intersectsBox( box );
 42034  
 42035  		},
 42036  		isIntersectionPlane: function ( plane ) {
 42037  
 42038  			console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' );
 42039  			return this.intersectsPlane( plane );
 42040  
 42041  		},
 42042  		isIntersectionSphere: function ( sphere ) {
 42043  
 42044  			console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' );
 42045  			return this.intersectsSphere( sphere );
 42046  
 42047  		}
 42048  
 42049  	} );
 42050  
 42051  	Object.assign( Shape.prototype, {
 42052  
 42053  		extrude: function ( options ) {
 42054  
 42055  			console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' );
 42056  			return new ExtrudeGeometry( this, options );
 42057  
 42058  		},
 42059  		makeGeometry: function ( options ) {
 42060  
 42061  			console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' );
 42062  			return new ShapeGeometry( this, options );
 42063  
 42064  		}
 42065  
 42066  	} );
 42067  
 42068  	Object.assign( Vector2.prototype, {
 42069  
 42070  		fromAttribute: function ( attribute, index, offset ) {
 42071  
 42072  			console.error( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' );
 42073  			return this.fromBufferAttribute( attribute, index, offset );
 42074  
 42075  		}
 42076  
 42077  	} );
 42078  
 42079  	Object.assign( Vector3.prototype, {
 42080  
 42081  		setEulerFromRotationMatrix: function () {
 42082  
 42083  			console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );
 42084  
 42085  		},
 42086  		setEulerFromQuaternion: function () {
 42087  
 42088  			console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );
 42089  
 42090  		},
 42091  		getPositionFromMatrix: function ( m ) {
 42092  
 42093  			console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );
 42094  			return this.setFromMatrixPosition( m );
 42095  
 42096  		},
 42097  		getScaleFromMatrix: function ( m ) {
 42098  
 42099  			console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );
 42100  			return this.setFromMatrixScale( m );
 42101  
 42102  		},
 42103  		getColumnFromMatrix: function ( index, matrix ) {
 42104  
 42105  			console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );
 42106  			return this.setFromMatrixColumn( matrix, index );
 42107  
 42108  		},
 42109  		applyProjection: function ( m ) {
 42110  
 42111  			console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' );
 42112  			return this.applyMatrix4( m );
 42113  
 42114  		},
 42115  		fromAttribute: function ( attribute, index, offset ) {
 42116  
 42117  			console.error( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' );
 42118  			return this.fromBufferAttribute( attribute, index, offset );
 42119  
 42120  		}
 42121  
 42122  	} );
 42123  
 42124  	Object.assign( Vector4.prototype, {
 42125  
 42126  		fromAttribute: function ( attribute, index, offset ) {
 42127  
 42128  			console.error( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );
 42129  			return this.fromBufferAttribute( attribute, index, offset );
 42130  
 42131  		}
 42132  
 42133  	} );
 42134  
 42135  	//
 42136  
 42137  	Geometry.prototype.computeTangents = function () {
 42138  
 42139  		console.warn( 'THREE.Geometry: .computeTangents() has been removed.' );
 42140  
 42141  	};
 42142  
 42143  	Object.assign( Object3D.prototype, {
 42144  
 42145  		getChildByName: function ( name ) {
 42146  
 42147  			console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );
 42148  			return this.getObjectByName( name );
 42149  
 42150  		},
 42151  		renderDepth: function () {
 42152  
 42153  			console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' );
 42154  
 42155  		},
 42156  		translate: function ( distance, axis ) {
 42157  
 42158  			console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );
 42159  			return this.translateOnAxis( axis, distance );
 42160  
 42161  		}
 42162  
 42163  	} );
 42164  
 42165  	Object.defineProperties( Object3D.prototype, {
 42166  
 42167  		eulerOrder: {
 42168  			get: function () {
 42169  
 42170  				console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
 42171  				return this.rotation.order;
 42172  
 42173  			},
 42174  			set: function ( value ) {
 42175  
 42176  				console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );
 42177  				this.rotation.order = value;
 42178  
 42179  			}
 42180  		},
 42181  		useQuaternion: {
 42182  			get: function () {
 42183  
 42184  				console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
 42185  
 42186  			},
 42187  			set: function () {
 42188  
 42189  				console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );
 42190  
 42191  			}
 42192  		}
 42193  
 42194  	} );
 42195  
 42196  	Object.defineProperties( LOD.prototype, {
 42197  
 42198  		objects: {
 42199  			get: function () {
 42200  
 42201  				console.warn( 'THREE.LOD: .objects has been renamed to .levels.' );
 42202  				return this.levels;
 42203  
 42204  			}
 42205  		}
 42206  
 42207  	} );
 42208  
 42209  	//
 42210  
 42211  	PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) {
 42212  
 42213  		console.warn( "THREE.PerspectiveCamera.setLens is deprecated. " +
 42214  				"Use .setFocalLength and .filmGauge for a photographic setup." );
 42215  
 42216  		if ( filmGauge !== undefined ) this.filmGauge = filmGauge;
 42217  		this.setFocalLength( focalLength );
 42218  
 42219  	};
 42220  
 42221  	//
 42222  
 42223  	Object.defineProperties( Light.prototype, {
 42224  		onlyShadow: {
 42225  			set: function () {
 42226  
 42227  				console.warn( 'THREE.Light: .onlyShadow has been removed.' );
 42228  
 42229  			}
 42230  		},
 42231  		shadowCameraFov: {
 42232  			set: function ( value ) {
 42233  
 42234  				console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' );
 42235  				this.shadow.camera.fov = value;
 42236  
 42237  			}
 42238  		},
 42239  		shadowCameraLeft: {
 42240  			set: function ( value ) {
 42241  
 42242  				console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' );
 42243  				this.shadow.camera.left = value;
 42244  
 42245  			}
 42246  		},
 42247  		shadowCameraRight: {
 42248  			set: function ( value ) {
 42249  
 42250  				console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' );
 42251  				this.shadow.camera.right = value;
 42252  
 42253  			}
 42254  		},
 42255  		shadowCameraTop: {
 42256  			set: function ( value ) {
 42257  
 42258  				console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' );
 42259  				this.shadow.camera.top = value;
 42260  
 42261  			}
 42262  		},
 42263  		shadowCameraBottom: {
 42264  			set: function ( value ) {
 42265  
 42266  				console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' );
 42267  				this.shadow.camera.bottom = value;
 42268  
 42269  			}
 42270  		},
 42271  		shadowCameraNear: {
 42272  			set: function ( value ) {
 42273  
 42274  				console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' );
 42275  				this.shadow.camera.near = value;
 42276  
 42277  			}
 42278  		},
 42279  		shadowCameraFar: {
 42280  			set: function ( value ) {
 42281  
 42282  				console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' );
 42283  				this.shadow.camera.far = value;
 42284  
 42285  			}
 42286  		},
 42287  		shadowCameraVisible: {
 42288  			set: function () {
 42289  
 42290  				console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' );
 42291  
 42292  			}
 42293  		},
 42294  		shadowBias: {
 42295  			set: function ( value ) {
 42296  
 42297  				console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' );
 42298  				this.shadow.bias = value;
 42299  
 42300  			}
 42301  		},
 42302  		shadowDarkness: {
 42303  			set: function () {
 42304  
 42305  				console.warn( 'THREE.Light: .shadowDarkness has been removed.' );
 42306  
 42307  			}
 42308  		},
 42309  		shadowMapWidth: {
 42310  			set: function ( value ) {
 42311  
 42312  				console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' );
 42313  				this.shadow.mapSize.width = value;
 42314  
 42315  			}
 42316  		},
 42317  		shadowMapHeight: {
 42318  			set: function ( value ) {
 42319  
 42320  				console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' );
 42321  				this.shadow.mapSize.height = value;
 42322  
 42323  			}
 42324  		}
 42325  	} );
 42326  
 42327  	//
 42328  
 42329  	Object.defineProperties( BufferAttribute.prototype, {
 42330  
 42331  		length: {
 42332  			get: function () {
 42333  
 42334  				console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' );
 42335  				return this.array.length;
 42336  
 42337  			}
 42338  		}
 42339  
 42340  	} );
 42341  
 42342  	Object.assign( BufferGeometry.prototype, {
 42343  
 42344  		addIndex: function ( index ) {
 42345  
 42346  			console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' );
 42347  			this.setIndex( index );
 42348  
 42349  		},
 42350  		addDrawCall: function ( start, count, indexOffset ) {
 42351  
 42352  			if ( indexOffset !== undefined ) {
 42353  
 42354  				console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' );
 42355  
 42356  			}
 42357  			console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' );
 42358  			this.addGroup( start, count );
 42359  
 42360  		},
 42361  		clearDrawCalls: function () {
 42362  
 42363  			console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' );
 42364  			this.clearGroups();
 42365  
 42366  		},
 42367  		computeTangents: function () {
 42368  
 42369  			console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' );
 42370  
 42371  		},
 42372  		computeOffsets: function () {
 42373  
 42374  			console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' );
 42375  
 42376  		}
 42377  
 42378  	} );
 42379  
 42380  	Object.defineProperties( BufferGeometry.prototype, {
 42381  
 42382  		drawcalls: {
 42383  			get: function () {
 42384  
 42385  				console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' );
 42386  				return this.groups;
 42387  
 42388  			}
 42389  		},
 42390  		offsets: {
 42391  			get: function () {
 42392  
 42393  				console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' );
 42394  				return this.groups;
 42395  
 42396  			}
 42397  		}
 42398  
 42399  	} );
 42400  
 42401  	//
 42402  
 42403  	Object.defineProperties( Uniform.prototype, {
 42404  
 42405  		dynamic: {
 42406  			set: function () {
 42407  
 42408  				console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' );
 42409  
 42410  			}
 42411  		},
 42412  		onUpdate: {
 42413  			value: function () {
 42414  
 42415  				console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' );
 42416  				return this;
 42417  
 42418  			}
 42419  		}
 42420  
 42421  	} );
 42422  
 42423  	//
 42424  
 42425  	Object.defineProperties( Material.prototype, {
 42426  
 42427  		wrapAround: {
 42428  			get: function () {
 42429  
 42430  				console.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' );
 42431  
 42432  			},
 42433  			set: function () {
 42434  
 42435  				console.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' );
 42436  
 42437  			}
 42438  		},
 42439  		wrapRGB: {
 42440  			get: function () {
 42441  
 42442  				console.warn( 'THREE.' + this.type + ': .wrapRGB has been removed.' );
 42443  				return new Color();
 42444  
 42445  			}
 42446  		}
 42447  
 42448  	} );
 42449  
 42450  	Object.defineProperties( MeshPhongMaterial.prototype, {
 42451  
 42452  		metal: {
 42453  			get: function () {
 42454  
 42455  				console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' );
 42456  				return false;
 42457  
 42458  			},
 42459  			set: function () {
 42460  
 42461  				console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' );
 42462  
 42463  			}
 42464  		}
 42465  
 42466  	} );
 42467  
 42468  	Object.defineProperties( ShaderMaterial.prototype, {
 42469  
 42470  		derivatives: {
 42471  			get: function () {
 42472  
 42473  				console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
 42474  				return this.extensions.derivatives;
 42475  
 42476  			},
 42477  			set: function ( value ) {
 42478  
 42479  				console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );
 42480  				this.extensions.derivatives = value;
 42481  
 42482  			}
 42483  		}
 42484  
 42485  	} );
 42486  
 42487  	//
 42488  
 42489  	Object.assign( WebGLRenderer.prototype, {
 42490  
 42491  		supportsFloatTextures: function () {
 42492  
 42493  			console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' );
 42494  			return this.extensions.get( 'OES_texture_float' );
 42495  
 42496  		},
 42497  		supportsHalfFloatTextures: function () {
 42498  
 42499  			console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' );
 42500  			return this.extensions.get( 'OES_texture_half_float' );
 42501  
 42502  		},
 42503  		supportsStandardDerivatives: function () {
 42504  
 42505  			console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' );
 42506  			return this.extensions.get( 'OES_standard_derivatives' );
 42507  
 42508  		},
 42509  		supportsCompressedTextureS3TC: function () {
 42510  
 42511  			console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' );
 42512  			return this.extensions.get( 'WEBGL_compressed_texture_s3tc' );
 42513  
 42514  		},
 42515  		supportsCompressedTexturePVRTC: function () {
 42516  
 42517  			console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' );
 42518  			return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' );
 42519  
 42520  		},
 42521  		supportsBlendMinMax: function () {
 42522  
 42523  			console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' );
 42524  			return this.extensions.get( 'EXT_blend_minmax' );
 42525  
 42526  		},
 42527  		supportsVertexTextures: function () {
 42528  
 42529  			console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' );
 42530  			return this.capabilities.vertexTextures;
 42531  
 42532  		},
 42533  		supportsInstancedArrays: function () {
 42534  
 42535  			console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' );
 42536  			return this.extensions.get( 'ANGLE_instanced_arrays' );
 42537  
 42538  		},
 42539  		enableScissorTest: function ( boolean ) {
 42540  
 42541  			console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' );
 42542  			this.setScissorTest( boolean );
 42543  
 42544  		},
 42545  		initMaterial: function () {
 42546  
 42547  			console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );
 42548  
 42549  		},
 42550  		addPrePlugin: function () {
 42551  
 42552  			console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );
 42553  
 42554  		},
 42555  		addPostPlugin: function () {
 42556  
 42557  			console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );
 42558  
 42559  		},
 42560  		updateShadowMap: function () {
 42561  
 42562  			console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );
 42563  
 42564  		}
 42565  
 42566  	} );
 42567  
 42568  	Object.defineProperties( WebGLRenderer.prototype, {
 42569  
 42570  		shadowMapEnabled: {
 42571  			get: function () {
 42572  
 42573  				return this.shadowMap.enabled;
 42574  
 42575  			},
 42576  			set: function ( value ) {
 42577  
 42578  				console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' );
 42579  				this.shadowMap.enabled = value;
 42580  
 42581  			}
 42582  		},
 42583  		shadowMapType: {
 42584  			get: function () {
 42585  
 42586  				return this.shadowMap.type;
 42587  
 42588  			},
 42589  			set: function ( value ) {
 42590  
 42591  				console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' );
 42592  				this.shadowMap.type = value;
 42593  
 42594  			}
 42595  		},
 42596  		shadowMapCullFace: {
 42597  			get: function () {
 42598  
 42599  				return this.shadowMap.cullFace;
 42600  
 42601  			},
 42602  			set: function ( value ) {
 42603  
 42604  				console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.' );
 42605  				this.shadowMap.cullFace = value;
 42606  
 42607  			}
 42608  		}
 42609  	} );
 42610  
 42611  	Object.defineProperties( WebGLShadowMap.prototype, {
 42612  
 42613  		cullFace: {
 42614  			get: function () {
 42615  
 42616  				return this.renderReverseSided ? CullFaceFront : CullFaceBack;
 42617  
 42618  			},
 42619  			set: function ( cullFace ) {
 42620  
 42621  				var value = ( cullFace !== CullFaceBack );
 42622  				console.warn( "WebGLRenderer: .shadowMap.cullFace is deprecated. Set .shadowMap.renderReverseSided to " + value + "." );
 42623  				this.renderReverseSided = value;
 42624  
 42625  			}
 42626  		}
 42627  
 42628  	} );
 42629  
 42630  	//
 42631  
 42632  	Object.defineProperties( WebGLRenderTarget.prototype, {
 42633  
 42634  		wrapS: {
 42635  			get: function () {
 42636  
 42637  				console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
 42638  				return this.texture.wrapS;
 42639  
 42640  			},
 42641  			set: function ( value ) {
 42642  
 42643  				console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );
 42644  				this.texture.wrapS = value;
 42645  
 42646  			}
 42647  		},
 42648  		wrapT: {
 42649  			get: function () {
 42650  
 42651  				console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
 42652  				return this.texture.wrapT;
 42653  
 42654  			},
 42655  			set: function ( value ) {
 42656  
 42657  				console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );
 42658  				this.texture.wrapT = value;
 42659  
 42660  			}
 42661  		},
 42662  		magFilter: {
 42663  			get: function () {
 42664  
 42665  				console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
 42666  				return this.texture.magFilter;
 42667  
 42668  			},
 42669  			set: function ( value ) {
 42670  
 42671  				console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );
 42672  				this.texture.magFilter = value;
 42673  
 42674  			}
 42675  		},
 42676  		minFilter: {
 42677  			get: function () {
 42678  
 42679  				console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
 42680  				return this.texture.minFilter;
 42681  
 42682  			},
 42683  			set: function ( value ) {
 42684  
 42685  				console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );
 42686  				this.texture.minFilter = value;
 42687  
 42688  			}
 42689  		},
 42690  		anisotropy: {
 42691  			get: function () {
 42692  
 42693  				console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
 42694  				return this.texture.anisotropy;
 42695  
 42696  			},
 42697  			set: function ( value ) {
 42698  
 42699  				console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );
 42700  				this.texture.anisotropy = value;
 42701  
 42702  			}
 42703  		},
 42704  		offset: {
 42705  			get: function () {
 42706  
 42707  				console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
 42708  				return this.texture.offset;
 42709  
 42710  			},
 42711  			set: function ( value ) {
 42712  
 42713  				console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );
 42714  				this.texture.offset = value;
 42715  
 42716  			}
 42717  		},
 42718  		repeat: {
 42719  			get: function () {
 42720  
 42721  				console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
 42722  				return this.texture.repeat;
 42723  
 42724  			},
 42725  			set: function ( value ) {
 42726  
 42727  				console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );
 42728  				this.texture.repeat = value;
 42729  
 42730  			}
 42731  		},
 42732  		format: {
 42733  			get: function () {
 42734  
 42735  				console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
 42736  				return this.texture.format;
 42737  
 42738  			},
 42739  			set: function ( value ) {
 42740  
 42741  				console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );
 42742  				this.texture.format = value;
 42743  
 42744  			}
 42745  		},
 42746  		type: {
 42747  			get: function () {
 42748  
 42749  				console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
 42750  				return this.texture.type;
 42751  
 42752  			},
 42753  			set: function ( value ) {
 42754  
 42755  				console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );
 42756  				this.texture.type = value;
 42757  
 42758  			}
 42759  		},
 42760  		generateMipmaps: {
 42761  			get: function () {
 42762  
 42763  				console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
 42764  				return this.texture.generateMipmaps;
 42765  
 42766  			},
 42767  			set: function ( value ) {
 42768  
 42769  				console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );
 42770  				this.texture.generateMipmaps = value;
 42771  
 42772  			}
 42773  		}
 42774  
 42775  	} );
 42776  
 42777  	//
 42778  
 42779  	Audio.prototype.load = function ( file ) {
 42780  
 42781  		console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' );
 42782  		var scope = this;
 42783  		var audioLoader = new AudioLoader();
 42784  		audioLoader.load( file, function ( buffer ) {
 42785  
 42786  			scope.setBuffer( buffer );
 42787  
 42788  		} );
 42789  		return this;
 42790  
 42791  	};
 42792  
 42793  	AudioAnalyser.prototype.getData = function () {
 42794  
 42795  		console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' );
 42796  		return this.getFrequencyData();
 42797  
 42798  	};
 42799  
 42800  	//
 42801  
 42802  	var GeometryUtils = {
 42803  
 42804  		merge: function ( geometry1, geometry2, materialIndexOffset ) {
 42805  
 42806  			console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );
 42807  			var matrix;
 42808  
 42809  			if ( geometry2.isMesh ) {
 42810  
 42811  				geometry2.matrixAutoUpdate && geometry2.updateMatrix();
 42812  
 42813  				matrix = geometry2.matrix;
 42814  				geometry2 = geometry2.geometry;
 42815  
 42816  			}
 42817  
 42818  			geometry1.merge( geometry2, matrix, materialIndexOffset );
 42819  
 42820  		},
 42821  
 42822  		center: function ( geometry ) {
 42823  
 42824  			console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );
 42825  			return geometry.center();
 42826  
 42827  		}
 42828  
 42829  	};
 42830  
 42831  	var ImageUtils = {
 42832  
 42833  		crossOrigin: undefined,
 42834  
 42835  		loadTexture: function ( url, mapping, onLoad, onError ) {
 42836  
 42837  			console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' );
 42838  
 42839  			var loader = new TextureLoader();
 42840  			loader.setCrossOrigin( this.crossOrigin );
 42841  
 42842  			var texture = loader.load( url, onLoad, undefined, onError );
 42843  
 42844  			if ( mapping ) texture.mapping = mapping;
 42845  
 42846  			return texture;
 42847  
 42848  		},
 42849  
 42850  		loadTextureCube: function ( urls, mapping, onLoad, onError ) {
 42851  
 42852  			console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' );
 42853  
 42854  			var loader = new CubeTextureLoader();
 42855  			loader.setCrossOrigin( this.crossOrigin );
 42856  
 42857  			var texture = loader.load( urls, onLoad, undefined, onError );
 42858  
 42859  			if ( mapping ) texture.mapping = mapping;
 42860  
 42861  			return texture;
 42862  
 42863  		},
 42864  
 42865  		loadCompressedTexture: function () {
 42866  
 42867  			console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' );
 42868  
 42869  		},
 42870  
 42871  		loadCompressedTextureCube: function () {
 42872  
 42873  			console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' );
 42874  
 42875  		}
 42876  
 42877  	};
 42878  
 42879  	//
 42880  
 42881  	function Projector() {
 42882  
 42883  		console.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' );
 42884  
 42885  		this.projectVector = function ( vector, camera ) {
 42886  
 42887  			console.warn( 'THREE.Projector: .projectVector() is now vector.project().' );
 42888  			vector.project( camera );
 42889  
 42890  		};
 42891  
 42892  		this.unprojectVector = function ( vector, camera ) {
 42893  
 42894  			console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );
 42895  			vector.unproject( camera );
 42896  
 42897  		};
 42898  
 42899  		this.pickingRay = function () {
 42900  
 42901  			console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );
 42902  
 42903  		};
 42904  
 42905  	}
 42906  
 42907  	//
 42908  
 42909  	function CanvasRenderer() {
 42910  
 42911  		console.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' );
 42912  
 42913  		this.domElement = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
 42914  		this.clear = function () {};
 42915  		this.render = function () {};
 42916  		this.setClearColor = function () {};
 42917  		this.setSize = function () {};
 42918  
 42919  	}
 42920  
 42921  	exports.WebGLRenderTargetCube = WebGLRenderTargetCube;
 42922  	exports.WebGLRenderTarget = WebGLRenderTarget;
 42923  	exports.WebGLRenderer = WebGLRenderer;
 42924  	exports.ShaderLib = ShaderLib;
 42925  	exports.UniformsLib = UniformsLib;
 42926  	exports.UniformsUtils = UniformsUtils;
 42927  	exports.ShaderChunk = ShaderChunk;
 42928  	exports.FogExp2 = FogExp2;
 42929  	exports.Fog = Fog;
 42930  	exports.Scene = Scene;
 42931  	exports.LensFlare = LensFlare;
 42932  	exports.Sprite = Sprite;
 42933  	exports.LOD = LOD;
 42934  	exports.SkinnedMesh = SkinnedMesh;
 42935  	exports.Skeleton = Skeleton;
 42936  	exports.Bone = Bone;
 42937  	exports.Mesh = Mesh;
 42938  	exports.LineSegments = LineSegments;
 42939  	exports.Line = Line;
 42940  	exports.Points = Points;
 42941  	exports.Group = Group;
 42942  	exports.VideoTexture = VideoTexture;
 42943  	exports.DataTexture = DataTexture;
 42944  	exports.CompressedTexture = CompressedTexture;
 42945  	exports.CubeTexture = CubeTexture;
 42946  	exports.CanvasTexture = CanvasTexture;
 42947  	exports.DepthTexture = DepthTexture;
 42948  	exports.Texture = Texture;
 42949  	exports.CompressedTextureLoader = CompressedTextureLoader;
 42950  	exports.DataTextureLoader = DataTextureLoader;
 42951  	exports.CubeTextureLoader = CubeTextureLoader;
 42952  	exports.TextureLoader = TextureLoader;
 42953  	exports.ObjectLoader = ObjectLoader;
 42954  	exports.MaterialLoader = MaterialLoader;
 42955  	exports.BufferGeometryLoader = BufferGeometryLoader;
 42956  	exports.DefaultLoadingManager = DefaultLoadingManager;
 42957  	exports.LoadingManager = LoadingManager;
 42958  	exports.JSONLoader = JSONLoader;
 42959  	exports.ImageLoader = ImageLoader;
 42960  	exports.FontLoader = FontLoader;
 42961  	exports.FileLoader = FileLoader;
 42962  	exports.Loader = Loader;
 42963  	exports.Cache = Cache;
 42964  	exports.AudioLoader = AudioLoader;
 42965  	exports.SpotLightShadow = SpotLightShadow;
 42966  	exports.SpotLight = SpotLight;
 42967  	exports.PointLight = PointLight;
 42968  	exports.RectAreaLight = RectAreaLight;
 42969  	exports.HemisphereLight = HemisphereLight;
 42970  	exports.DirectionalLightShadow = DirectionalLightShadow;
 42971  	exports.DirectionalLight = DirectionalLight;
 42972  	exports.AmbientLight = AmbientLight;
 42973  	exports.LightShadow = LightShadow;
 42974  	exports.Light = Light;
 42975  	exports.StereoCamera = StereoCamera;
 42976  	exports.PerspectiveCamera = PerspectiveCamera;
 42977  	exports.OrthographicCamera = OrthographicCamera;
 42978  	exports.CubeCamera = CubeCamera;
 42979  	exports.Camera = Camera;
 42980  	exports.AudioListener = AudioListener;
 42981  	exports.PositionalAudio = PositionalAudio;
 42982  	exports.AudioContext = AudioContext;
 42983  	exports.AudioAnalyser = AudioAnalyser;
 42984  	exports.Audio = Audio;
 42985  	exports.VectorKeyframeTrack = VectorKeyframeTrack;
 42986  	exports.StringKeyframeTrack = StringKeyframeTrack;
 42987  	exports.QuaternionKeyframeTrack = QuaternionKeyframeTrack;
 42988  	exports.NumberKeyframeTrack = NumberKeyframeTrack;
 42989  	exports.ColorKeyframeTrack = ColorKeyframeTrack;
 42990  	exports.BooleanKeyframeTrack = BooleanKeyframeTrack;
 42991  	exports.PropertyMixer = PropertyMixer;
 42992  	exports.PropertyBinding = PropertyBinding;
 42993  	exports.KeyframeTrack = KeyframeTrack;
 42994  	exports.AnimationUtils = AnimationUtils;
 42995  	exports.AnimationObjectGroup = AnimationObjectGroup;
 42996  	exports.AnimationMixer = AnimationMixer;
 42997  	exports.AnimationClip = AnimationClip;
 42998  	exports.Uniform = Uniform;
 42999  	exports.InstancedBufferGeometry = InstancedBufferGeometry;
 43000  	exports.BufferGeometry = BufferGeometry;
 43001  	exports.GeometryIdCount = GeometryIdCount;
 43002  	exports.Geometry = Geometry;
 43003  	exports.InterleavedBufferAttribute = InterleavedBufferAttribute;
 43004  	exports.InstancedInterleavedBuffer = InstancedInterleavedBuffer;
 43005  	exports.InterleavedBuffer = InterleavedBuffer;
 43006  	exports.InstancedBufferAttribute = InstancedBufferAttribute;
 43007  	exports.Face3 = Face3;
 43008  	exports.Object3D = Object3D;
 43009  	exports.Raycaster = Raycaster;
 43010  	exports.Layers = Layers;
 43011  	exports.EventDispatcher = EventDispatcher;
 43012  	exports.Clock = Clock;
 43013  	exports.QuaternionLinearInterpolant = QuaternionLinearInterpolant;
 43014  	exports.LinearInterpolant = LinearInterpolant;
 43015  	exports.DiscreteInterpolant = DiscreteInterpolant;
 43016  	exports.CubicInterpolant = CubicInterpolant;
 43017  	exports.Interpolant = Interpolant;
 43018  	exports.Triangle = Triangle;
 43019  	exports.Math = _Math;
 43020  	exports.Spherical = Spherical;
 43021  	exports.Cylindrical = Cylindrical;
 43022  	exports.Plane = Plane;
 43023  	exports.Frustum = Frustum;
 43024  	exports.Sphere = Sphere;
 43025  	exports.Ray = Ray;
 43026  	exports.Matrix4 = Matrix4;
 43027  	exports.Matrix3 = Matrix3;
 43028  	exports.Box3 = Box3;
 43029  	exports.Box2 = Box2;
 43030  	exports.Line3 = Line3;
 43031  	exports.Euler = Euler;
 43032  	exports.Vector4 = Vector4;
 43033  	exports.Vector3 = Vector3;
 43034  	exports.Vector2 = Vector2;
 43035  	exports.Quaternion = Quaternion;
 43036  	exports.Color = Color;
 43037  	exports.MorphBlendMesh = MorphBlendMesh;
 43038  	exports.ImmediateRenderObject = ImmediateRenderObject;
 43039  	exports.VertexNormalsHelper = VertexNormalsHelper;
 43040  	exports.SpotLightHelper = SpotLightHelper;
 43041  	exports.SkeletonHelper = SkeletonHelper;
 43042  	exports.PointLightHelper = PointLightHelper;
 43043  	exports.RectAreaLightHelper = RectAreaLightHelper;
 43044  	exports.HemisphereLightHelper = HemisphereLightHelper;
 43045  	exports.GridHelper = GridHelper;
 43046  	exports.PolarGridHelper = PolarGridHelper;
 43047  	exports.FaceNormalsHelper = FaceNormalsHelper;
 43048  	exports.DirectionalLightHelper = DirectionalLightHelper;
 43049  	exports.CameraHelper = CameraHelper;
 43050  	exports.BoxHelper = BoxHelper;
 43051  	exports.ArrowHelper = ArrowHelper;
 43052  	exports.AxisHelper = AxisHelper;
 43053  	exports.CatmullRomCurve3 = CatmullRomCurve3;
 43054  	exports.CubicBezierCurve3 = CubicBezierCurve3;
 43055  	exports.QuadraticBezierCurve3 = QuadraticBezierCurve3;
 43056  	exports.LineCurve3 = LineCurve3;
 43057  	exports.ArcCurve = ArcCurve;
 43058  	exports.EllipseCurve = EllipseCurve;
 43059  	exports.SplineCurve = SplineCurve;
 43060  	exports.CubicBezierCurve = CubicBezierCurve;
 43061  	exports.QuadraticBezierCurve = QuadraticBezierCurve;
 43062  	exports.LineCurve = LineCurve;
 43063  	exports.Shape = Shape;
 43064  	exports.Path = Path;
 43065  	exports.ShapePath = ShapePath;
 43066  	exports.Font = Font;
 43067  	exports.CurvePath = CurvePath;
 43068  	exports.Curve = Curve;
 43069  	exports.ShapeUtils = ShapeUtils;
 43070  	exports.SceneUtils = SceneUtils;
 43071  	exports.WireframeGeometry = WireframeGeometry;
 43072  	exports.ParametricGeometry = ParametricGeometry;
 43073  	exports.ParametricBufferGeometry = ParametricBufferGeometry;
 43074  	exports.TetrahedronGeometry = TetrahedronGeometry;
 43075  	exports.TetrahedronBufferGeometry = TetrahedronBufferGeometry;
 43076  	exports.OctahedronGeometry = OctahedronGeometry;
 43077  	exports.OctahedronBufferGeometry = OctahedronBufferGeometry;
 43078  	exports.IcosahedronGeometry = IcosahedronGeometry;
 43079  	exports.IcosahedronBufferGeometry = IcosahedronBufferGeometry;
 43080  	exports.DodecahedronGeometry = DodecahedronGeometry;
 43081  	exports.DodecahedronBufferGeometry = DodecahedronBufferGeometry;
 43082  	exports.PolyhedronGeometry = PolyhedronGeometry;
 43083  	exports.PolyhedronBufferGeometry = PolyhedronBufferGeometry;
 43084  	exports.TubeGeometry = TubeGeometry;
 43085  	exports.TubeBufferGeometry = TubeBufferGeometry;
 43086  	exports.TorusKnotGeometry = TorusKnotGeometry;
 43087  	exports.TorusKnotBufferGeometry = TorusKnotBufferGeometry;
 43088  	exports.TorusGeometry = TorusGeometry;
 43089  	exports.TorusBufferGeometry = TorusBufferGeometry;
 43090  	exports.TextGeometry = TextGeometry;
 43091  	exports.SphereGeometry = SphereGeometry;
 43092  	exports.SphereBufferGeometry = SphereBufferGeometry;
 43093  	exports.RingGeometry = RingGeometry;
 43094  	exports.RingBufferGeometry = RingBufferGeometry;
 43095  	exports.PlaneGeometry = PlaneGeometry;
 43096  	exports.PlaneBufferGeometry = PlaneBufferGeometry;
 43097  	exports.LatheGeometry = LatheGeometry;
 43098  	exports.LatheBufferGeometry = LatheBufferGeometry;
 43099  	exports.ShapeGeometry = ShapeGeometry;
 43100  	exports.ShapeBufferGeometry = ShapeBufferGeometry;
 43101  	exports.ExtrudeGeometry = ExtrudeGeometry;
 43102  	exports.EdgesGeometry = EdgesGeometry;
 43103  	exports.ConeGeometry = ConeGeometry;
 43104  	exports.ConeBufferGeometry = ConeBufferGeometry;
 43105  	exports.CylinderGeometry = CylinderGeometry;
 43106  	exports.CylinderBufferGeometry = CylinderBufferGeometry;
 43107  	exports.CircleGeometry = CircleGeometry;
 43108  	exports.CircleBufferGeometry = CircleBufferGeometry;
 43109  	exports.BoxGeometry = BoxGeometry;
 43110  	exports.BoxBufferGeometry = BoxBufferGeometry;
 43111  	exports.ShadowMaterial = ShadowMaterial;
 43112  	exports.SpriteMaterial = SpriteMaterial;
 43113  	exports.RawShaderMaterial = RawShaderMaterial;
 43114  	exports.ShaderMaterial = ShaderMaterial;
 43115  	exports.PointsMaterial = PointsMaterial;
 43116  	exports.MultiMaterial = MultiMaterial;
 43117  	exports.MeshPhysicalMaterial = MeshPhysicalMaterial;
 43118  	exports.MeshStandardMaterial = MeshStandardMaterial;
 43119  	exports.MeshPhongMaterial = MeshPhongMaterial;
 43120  	exports.MeshToonMaterial = MeshToonMaterial;
 43121  	exports.MeshNormalMaterial = MeshNormalMaterial;
 43122  	exports.MeshLambertMaterial = MeshLambertMaterial;
 43123  	exports.MeshDepthMaterial = MeshDepthMaterial;
 43124  	exports.MeshBasicMaterial = MeshBasicMaterial;
 43125  	exports.LineDashedMaterial = LineDashedMaterial;
 43126  	exports.LineBasicMaterial = LineBasicMaterial;
 43127  	exports.Material = Material;
 43128  	exports.Float64BufferAttribute = Float64BufferAttribute;
 43129  	exports.Float32BufferAttribute = Float32BufferAttribute;
 43130  	exports.Uint32BufferAttribute = Uint32BufferAttribute;
 43131  	exports.Int32BufferAttribute = Int32BufferAttribute;
 43132  	exports.Uint16BufferAttribute = Uint16BufferAttribute;
 43133  	exports.Int16BufferAttribute = Int16BufferAttribute;
 43134  	exports.Uint8ClampedBufferAttribute = Uint8ClampedBufferAttribute;
 43135  	exports.Uint8BufferAttribute = Uint8BufferAttribute;
 43136  	exports.Int8BufferAttribute = Int8BufferAttribute;
 43137  	exports.BufferAttribute = BufferAttribute;
 43138  	exports.REVISION = REVISION;
 43139  	exports.MOUSE = MOUSE;
 43140  	exports.CullFaceNone = CullFaceNone;
 43141  	exports.CullFaceBack = CullFaceBack;
 43142  	exports.CullFaceFront = CullFaceFront;
 43143  	exports.CullFaceFrontBack = CullFaceFrontBack;
 43144  	exports.FrontFaceDirectionCW = FrontFaceDirectionCW;
 43145  	exports.FrontFaceDirectionCCW = FrontFaceDirectionCCW;
 43146  	exports.BasicShadowMap = BasicShadowMap;
 43147  	exports.PCFShadowMap = PCFShadowMap;
 43148  	exports.PCFSoftShadowMap = PCFSoftShadowMap;
 43149  	exports.FrontSide = FrontSide;
 43150  	exports.BackSide = BackSide;
 43151  	exports.DoubleSide = DoubleSide;
 43152  	exports.FlatShading = FlatShading;
 43153  	exports.SmoothShading = SmoothShading;
 43154  	exports.NoColors = NoColors;
 43155  	exports.FaceColors = FaceColors;
 43156  	exports.VertexColors = VertexColors;
 43157  	exports.NoBlending = NoBlending;
 43158  	exports.NormalBlending = NormalBlending;
 43159  	exports.AdditiveBlending = AdditiveBlending;
 43160  	exports.SubtractiveBlending = SubtractiveBlending;
 43161  	exports.MultiplyBlending = MultiplyBlending;
 43162  	exports.CustomBlending = CustomBlending;
 43163  	exports.AddEquation = AddEquation;
 43164  	exports.SubtractEquation = SubtractEquation;
 43165  	exports.ReverseSubtractEquation = ReverseSubtractEquation;
 43166  	exports.MinEquation = MinEquation;
 43167  	exports.MaxEquation = MaxEquation;
 43168  	exports.ZeroFactor = ZeroFactor;
 43169  	exports.OneFactor = OneFactor;
 43170  	exports.SrcColorFactor = SrcColorFactor;
 43171  	exports.OneMinusSrcColorFactor = OneMinusSrcColorFactor;
 43172  	exports.SrcAlphaFactor = SrcAlphaFactor;
 43173  	exports.OneMinusSrcAlphaFactor = OneMinusSrcAlphaFactor;
 43174  	exports.DstAlphaFactor = DstAlphaFactor;
 43175  	exports.OneMinusDstAlphaFactor = OneMinusDstAlphaFactor;
 43176  	exports.DstColorFactor = DstColorFactor;
 43177  	exports.OneMinusDstColorFactor = OneMinusDstColorFactor;
 43178  	exports.SrcAlphaSaturateFactor = SrcAlphaSaturateFactor;
 43179  	exports.NeverDepth = NeverDepth;
 43180  	exports.AlwaysDepth = AlwaysDepth;
 43181  	exports.LessDepth = LessDepth;
 43182  	exports.LessEqualDepth = LessEqualDepth;
 43183  	exports.EqualDepth = EqualDepth;
 43184  	exports.GreaterEqualDepth = GreaterEqualDepth;
 43185  	exports.GreaterDepth = GreaterDepth;
 43186  	exports.NotEqualDepth = NotEqualDepth;
 43187  	exports.MultiplyOperation = MultiplyOperation;
 43188  	exports.MixOperation = MixOperation;
 43189  	exports.AddOperation = AddOperation;
 43190  	exports.NoToneMapping = NoToneMapping;
 43191  	exports.LinearToneMapping = LinearToneMapping;
 43192  	exports.ReinhardToneMapping = ReinhardToneMapping;
 43193  	exports.Uncharted2ToneMapping = Uncharted2ToneMapping;
 43194  	exports.CineonToneMapping = CineonToneMapping;
 43195  	exports.UVMapping = UVMapping;
 43196  	exports.CubeReflectionMapping = CubeReflectionMapping;
 43197  	exports.CubeRefractionMapping = CubeRefractionMapping;
 43198  	exports.EquirectangularReflectionMapping = EquirectangularReflectionMapping;
 43199  	exports.EquirectangularRefractionMapping = EquirectangularRefractionMapping;
 43200  	exports.SphericalReflectionMapping = SphericalReflectionMapping;
 43201  	exports.CubeUVReflectionMapping = CubeUVReflectionMapping;
 43202  	exports.CubeUVRefractionMapping = CubeUVRefractionMapping;
 43203  	exports.RepeatWrapping = RepeatWrapping;
 43204  	exports.ClampToEdgeWrapping = ClampToEdgeWrapping;
 43205  	exports.MirroredRepeatWrapping = MirroredRepeatWrapping;
 43206  	exports.NearestFilter = NearestFilter;
 43207  	exports.NearestMipMapNearestFilter = NearestMipMapNearestFilter;
 43208  	exports.NearestMipMapLinearFilter = NearestMipMapLinearFilter;
 43209  	exports.LinearFilter = LinearFilter;
 43210  	exports.LinearMipMapNearestFilter = LinearMipMapNearestFilter;
 43211  	exports.LinearMipMapLinearFilter = LinearMipMapLinearFilter;
 43212  	exports.UnsignedByteType = UnsignedByteType;
 43213  	exports.ByteType = ByteType;
 43214  	exports.ShortType = ShortType;
 43215  	exports.UnsignedShortType = UnsignedShortType;
 43216  	exports.IntType = IntType;
 43217  	exports.UnsignedIntType = UnsignedIntType;
 43218  	exports.FloatType = FloatType;
 43219  	exports.HalfFloatType = HalfFloatType;
 43220  	exports.UnsignedShort4444Type = UnsignedShort4444Type;
 43221  	exports.UnsignedShort5551Type = UnsignedShort5551Type;
 43222  	exports.UnsignedShort565Type = UnsignedShort565Type;
 43223  	exports.UnsignedInt248Type = UnsignedInt248Type;
 43224  	exports.AlphaFormat = AlphaFormat;
 43225  	exports.RGBFormat = RGBFormat;
 43226  	exports.RGBAFormat = RGBAFormat;
 43227  	exports.LuminanceFormat = LuminanceFormat;
 43228  	exports.LuminanceAlphaFormat = LuminanceAlphaFormat;
 43229  	exports.RGBEFormat = RGBEFormat;
 43230  	exports.DepthFormat = DepthFormat;
 43231  	exports.DepthStencilFormat = DepthStencilFormat;
 43232  	exports.RGB_S3TC_DXT1_Format = RGB_S3TC_DXT1_Format;
 43233  	exports.RGBA_S3TC_DXT1_Format = RGBA_S3TC_DXT1_Format;
 43234  	exports.RGBA_S3TC_DXT3_Format = RGBA_S3TC_DXT3_Format;
 43235  	exports.RGBA_S3TC_DXT5_Format = RGBA_S3TC_DXT5_Format;
 43236  	exports.RGB_PVRTC_4BPPV1_Format = RGB_PVRTC_4BPPV1_Format;
 43237  	exports.RGB_PVRTC_2BPPV1_Format = RGB_PVRTC_2BPPV1_Format;
 43238  	exports.RGBA_PVRTC_4BPPV1_Format = RGBA_PVRTC_4BPPV1_Format;
 43239  	exports.RGBA_PVRTC_2BPPV1_Format = RGBA_PVRTC_2BPPV1_Format;
 43240  	exports.RGB_ETC1_Format = RGB_ETC1_Format;
 43241  	exports.LoopOnce = LoopOnce;
 43242  	exports.LoopRepeat = LoopRepeat;
 43243  	exports.LoopPingPong = LoopPingPong;
 43244  	exports.InterpolateDiscrete = InterpolateDiscrete;
 43245  	exports.InterpolateLinear = InterpolateLinear;
 43246  	exports.InterpolateSmooth = InterpolateSmooth;
 43247  	exports.ZeroCurvatureEnding = ZeroCurvatureEnding;
 43248  	exports.ZeroSlopeEnding = ZeroSlopeEnding;
 43249  	exports.WrapAroundEnding = WrapAroundEnding;
 43250  	exports.TrianglesDrawMode = TrianglesDrawMode;
 43251  	exports.TriangleStripDrawMode = TriangleStripDrawMode;
 43252  	exports.TriangleFanDrawMode = TriangleFanDrawMode;
 43253  	exports.LinearEncoding = LinearEncoding;
 43254  	exports.sRGBEncoding = sRGBEncoding;
 43255  	exports.GammaEncoding = GammaEncoding;
 43256  	exports.RGBEEncoding = RGBEEncoding;
 43257  	exports.LogLuvEncoding = LogLuvEncoding;
 43258  	exports.RGBM7Encoding = RGBM7Encoding;
 43259  	exports.RGBM16Encoding = RGBM16Encoding;
 43260  	exports.RGBDEncoding = RGBDEncoding;
 43261  	exports.BasicDepthPacking = BasicDepthPacking;
 43262  	exports.RGBADepthPacking = RGBADepthPacking;
 43263  	exports.CubeGeometry = BoxGeometry;
 43264  	exports.Face4 = Face4;
 43265  	exports.LineStrip = LineStrip;
 43266  	exports.LinePieces = LinePieces;
 43267  	exports.MeshFaceMaterial = MeshFaceMaterial;
 43268  	exports.PointCloud = PointCloud;
 43269  	exports.Particle = Particle;
 43270  	exports.ParticleSystem = ParticleSystem;
 43271  	exports.PointCloudMaterial = PointCloudMaterial;
 43272  	exports.ParticleBasicMaterial = ParticleBasicMaterial;
 43273  	exports.ParticleSystemMaterial = ParticleSystemMaterial;
 43274  	exports.Vertex = Vertex;
 43275  	exports.DynamicBufferAttribute = DynamicBufferAttribute;
 43276  	exports.Int8Attribute = Int8Attribute;
 43277  	exports.Uint8Attribute = Uint8Attribute;
 43278  	exports.Uint8ClampedAttribute = Uint8ClampedAttribute;
 43279  	exports.Int16Attribute = Int16Attribute;
 43280  	exports.Uint16Attribute = Uint16Attribute;
 43281  	exports.Int32Attribute = Int32Attribute;
 43282  	exports.Uint32Attribute = Uint32Attribute;
 43283  	exports.Float32Attribute = Float32Attribute;
 43284  	exports.Float64Attribute = Float64Attribute;
 43285  	exports.ClosedSplineCurve3 = ClosedSplineCurve3;
 43286  	exports.SplineCurve3 = SplineCurve3;
 43287  	exports.Spline = Spline;
 43288  	exports.BoundingBoxHelper = BoundingBoxHelper;
 43289  	exports.EdgesHelper = EdgesHelper;
 43290  	exports.WireframeHelper = WireframeHelper;
 43291  	exports.XHRLoader = XHRLoader;
 43292  	exports.BinaryTextureLoader = BinaryTextureLoader;
 43293  	exports.GeometryUtils = GeometryUtils;
 43294  	exports.ImageUtils = ImageUtils;
 43295  	exports.Projector = Projector;
 43296  	exports.CanvasRenderer = CanvasRenderer;
 43297  
 43298  	Object.defineProperty(exports, '__esModule', { value: true });
 43299  
 43300  })));