From abf61f1e2f4a83ccb42a0eff1098d936b299272d Mon Sep 17 00:00:00 2001 From: Rob Scanlon Date: Fri, 26 Feb 2016 22:35:36 -0500 Subject: [PATCH 1/5] add onmouse* handlers to rotate globe --- build/encom-globe.js | 3923 +++++++++++++++++++++++++++++++-------- display/display-data.js | 18 + display/display.html | 21 + display/display.js | 79 + display/styles.css | 13 + src/Globe.js | 65 +- 6 files changed, 3374 insertions(+), 745 deletions(-) create mode 100644 display/display-data.js create mode 100644 display/display.html create mode 100644 display/display.js create mode 100644 display/styles.css diff --git a/build/encom-globe.js b/build/encom-globe.js index fb3c726..9e3d2ae 100644 --- a/build/encom-globe.js +++ b/build/encom-globe.js @@ -2859,7 +2859,7 @@ var self = self || {};/** * @author bhouston / http://exocortex.com */ -var THREE = { REVISION: '66' }; +var THREE = { REVISION: '66.87' }; self.console = self.console || { @@ -2910,6 +2910,32 @@ self.console = self.console || { }() ); +THREE.ExceptionErrorHandler = function( message, optionalData ) { + console.error( message ); + console.error( optionalData ); + var error = new Error( message ); + error.optionalData = optionalData; + throw error; +}; + +THREE.ConsoleErrorHandler = function( message, optionalData ) { + console.error( message ); + console.error( optionalData ); +}; + +THREE.ConsoleWarningHandler = function( message, optionalData ) { + console.warn( message ); + console.warn( optionalData ); +}; + +THREE.NullHandler = function( message, optionalData ) { +}; + +// the default error handler is exception +THREE.onerror = THREE.ExceptionErrorHandler; + +THREE.onwarning = THREE.ConsoleWarningHandler; + // GL STATE CONSTANTS THREE.CullFaceNone = 0; @@ -3018,6 +3044,15 @@ THREE.LinearFilter = 1006; THREE.LinearMipMapNearestFilter = 1007; THREE.LinearMipMapLinearFilter = 1008; +// Texture Decoders + +THREE.Linear = 3000; +THREE.sRGB = 3001; +THREE.RGBE = 3002; +THREE.LogLUV = 3003; +THREE.RGBM7 = 3004; +THREE.RGBM16 = 3005; + // Data types THREE.UnsignedByteType = 1009; @@ -3027,6 +3062,7 @@ THREE.UnsignedShortType = 1012; THREE.IntType = 1013; THREE.UnsignedIntType = 1014; THREE.FloatType = 1015; +THREE.HalfType = 2005; // Pixel types @@ -3057,6 +3093,7 @@ THREE.RGB_PVRTC_2BPPV1_Format = 2101; THREE.RGBA_PVRTC_4BPPV1_Format = 2102; THREE.RGBA_PVRTC_2BPPV1_Format = 2103; */ + /** * @author mrdoob / http://mrdoob.com/ */ @@ -3463,6 +3500,7 @@ THREE.ColorKeywords = { "aliceblue": 0xF0F8FF, "antiquewhite": 0xFAEBD7, "aqua": "sienna": 0xA0522D, "silver": 0xC0C0C0, "skyblue": 0x87CEEB, "slateblue": 0x6A5ACD, "slategray": 0x708090, "slategrey": 0x708090, "snow": 0xFFFAFA, "springgreen": 0x00FF7F, "steelblue": 0x4682B4, "tan": 0xD2B48C, "teal": 0x008080, "thistle": 0xD8BFD8, "tomato": 0xFF6347, "turquoise": 0x40E0D0, "violet": 0xEE82EE, "wheat": 0xF5DEB3, "white": 0xFFFFFF, "whitesmoke": 0xF5F5F5, "yellow": 0xFFFF00, "yellowgreen": 0x9ACD32 }; + /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ @@ -3577,10 +3615,7 @@ THREE.Quaternion.prototype = { setFromEuler: function ( euler, update ) { - if ( euler instanceof THREE.Euler === false ) { - - throw new Error( 'ERROR: Quaternion\'s .setFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); - } + if ( ! ( euler instanceof THREE.Euler ) ) return THREE.onerror( 'expecting a Euler', euler ); // http://www.mathworks.com/matlabcentral/fileexchange/ // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ @@ -3663,9 +3698,11 @@ THREE.Quaternion.prototype = { setFromRotationMatrix: function ( m ) { + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) var te = m.elements, @@ -3727,6 +3764,39 @@ THREE.Quaternion.prototype = { return this; }, + + add: function ( q ) { + + this._x += q._x; + this._y += q._y; + this._z += q._z; + this._w += q._w; + + return this; + + }, + + sub: function ( q ) { + + this._x -= q._x; + this._y -= q._y; + this._z -= q._z; + this._w -= q._w; + + return this; + + }, + + multiplyScalar: function ( s ) { + + this._x *= s; + this._y *= s; + this._z *= s; + this._w *= s; + + return this; + + }, conjugate: function () { @@ -3782,7 +3852,7 @@ THREE.Quaternion.prototype = { if ( p !== undefined ) { - console.warn( 'DEPRECATED: Quaternion\'s .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); + THREE.onwarning( 'DEPRECATED: Quaternion\'s .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); return this.multiplyQuaternions( q, p ); } @@ -3811,7 +3881,7 @@ THREE.Quaternion.prototype = { multiplyVector3: function ( vector ) { - console.warn( 'DEPRECATED: Quaternion\'s .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); + THREE.onwarning( 'DEPRECATED: Quaternion\'s .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); return vector.applyQuaternion( this ); }, @@ -3916,6 +3986,7 @@ THREE.Quaternion.slerp = function ( qa, qb, qm, t ) { return qm.copy( qa ).slerp( qb, t ); } + /** * @author mrdoob / http://mrdoob.com/ * @author philogb / http://blog.thejit.org/ @@ -3966,7 +4037,7 @@ THREE.Vector2.prototype = { case 0: this.x = value; break; case 1: this.y = value; break; - default: throw new Error( "index is out of range: " + index ); + default: return THREE.onerror( 'index is out of range: ' + index ); } @@ -3978,7 +4049,7 @@ THREE.Vector2.prototype = { case 0: return this.x; case 1: return this.y; - default: throw new Error( "index is out of range: " + index ); + default: return THREE.onerror( 'index is out of range: ' + index ); } @@ -3997,7 +4068,7 @@ THREE.Vector2.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector2\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + THREE.onwarning( 'DEPRECATED: Vector2\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } @@ -4031,7 +4102,7 @@ THREE.Vector2.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector2\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + THREE.onwarning( 'DEPRECATED: Vector2\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } @@ -4295,6 +4366,7 @@ THREE.Vector2.prototype = { } }; + /** * @author mrdoob / http://mrdoob.com/ * @author *kile / http://kile.stravaganza.org/ @@ -4357,7 +4429,7 @@ THREE.Vector3.prototype = { case 0: this.x = value; break; case 1: this.y = value; break; case 2: this.z = value; break; - default: throw new Error( "index is out of range: " + index ); + default: return THREE.onerror( 'index is out of range: ' + index ); } @@ -4370,7 +4442,7 @@ THREE.Vector3.prototype = { case 0: return this.x; case 1: return this.y; case 2: return this.z; - default: throw new Error( "index is out of range: " + index ); + default: return THREE.onerror( 'index is out of range: ' + index ); } @@ -4390,7 +4462,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector3\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + THREE.onwarning( 'DEPRECATED: Vector3\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } @@ -4427,7 +4499,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector3\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + THREE.onwarningn( 'DEPRECATED: Vector3\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } @@ -4454,7 +4526,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector3\'s .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); + THREE.onwarning( 'DEPRECATED: Vector3\'s .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); return this.multiplyVectors( v, w ); } @@ -4493,11 +4565,7 @@ THREE.Vector3.prototype = { return function ( euler ) { - if ( euler instanceof THREE.Euler === false ) { - - console.error( 'ERROR: Vector3\'s .applyEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); - - } + if ( ! ( euler instanceof THREE.Euler ) ) return THREE.onerror( 'expecting an Euler', euler ); if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); @@ -4527,6 +4595,8 @@ THREE.Vector3.prototype = { applyMatrix3: function ( m ) { + //if ( ! ( m instanceof THREE.Matrix3 ) ) return THREE.onerror( 'expecting an Matrix3', m ); + var x = this.x; var y = this.y; var z = this.z; @@ -4544,6 +4614,7 @@ THREE.Vector3.prototype = { applyMatrix4: function ( m ) { // input: THREE.Matrix4 affine matrix + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting an Matrix4', m ); var x = this.x, y = this.y, z = this.z; @@ -4560,6 +4631,7 @@ THREE.Vector3.prototype = { applyProjection: function ( m ) { // input: THREE.Matrix4 projection matrix + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting an Matrix4', m ); var x = this.x, y = this.y, z = this.z; @@ -4864,7 +4936,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector3\'s .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); + THREE.onwarning( 'DEPRECATED: Vector3\'s .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); return this.crossVectors( v, w ); } @@ -4971,19 +5043,19 @@ THREE.Vector3.prototype = { setEulerFromRotationMatrix: function ( m, order ) { - console.error( "REMOVED: Vector3\'s setEulerFromRotationMatrix has been removed in favor of Euler.setFromRotationMatrix(), please update your code."); + THREE.onerror( "REMOVED: Vector3\'s setEulerFromRotationMatrix has been removed in favor of Euler.setFromRotationMatrix(), please update your code."); }, setEulerFromQuaternion: function ( q, order ) { - console.error( "REMOVED: Vector3\'s setEulerFromQuaternion: has been removed in favor of Euler.setFromQuaternion(), please update your code."); + THREE.onerror( "REMOVED: Vector3\'s setEulerFromQuaternion: has been removed in favor of Euler.setFromQuaternion(), please update your code."); }, getPositionFromMatrix: function ( m ) { - console.warn( "DEPRECATED: Vector3\'s .getPositionFromMatrix() has been renamed to .setFromMatrixPosition(). Please update your code." ); + THREE.onwarning( "DEPRECATED: Vector3\'s .getPositionFromMatrix() has been renamed to .setFromMatrixPosition(). Please update your code." ); return this.setFromMatrixPosition( m ); @@ -4991,14 +5063,14 @@ THREE.Vector3.prototype = { getScaleFromMatrix: function ( m ) { - console.warn( "DEPRECATED: Vector3\'s .getScaleFromMatrix() has been renamed to .setFromMatrixScale(). Please update your code." ); + THREE.onwarning( "DEPRECATED: Vector3\'s .getScaleFromMatrix() has been renamed to .setFromMatrixScale(). Please update your code." ); return this.setFromMatrixScale( m ); }, getColumnFromMatrix: function ( index, matrix ) { - console.warn( "DEPRECATED: Vector3\'s .getColumnFromMatrix() has been renamed to .setFromMatrixColumn(). Please update your code." ); + THREE.onwarning( "DEPRECATED: Vector3\'s .getColumnFromMatrix() has been renamed to .setFromMatrixColumn(). Please update your code." ); return this.setFromMatrixColumn( index, matrix ); @@ -5069,7 +5141,8 @@ THREE.Vector3.prototype = { } -};/** +}; +/** * @author supereggbert / http://www.paulbrunt.co.uk/ * @author philogb / http://blog.thejit.org/ * @author mikael emtinger / http://gomo.se/ @@ -5141,7 +5214,7 @@ THREE.Vector4.prototype = { case 1: this.y = value; break; case 2: this.z = value; break; case 3: this.w = value; break; - default: throw new Error( "index is out of range: " + index ); + default: return THREE.onerror( 'index is out of range: ' + index ); } @@ -5155,7 +5228,7 @@ THREE.Vector4.prototype = { case 1: return this.y; case 2: return this.z; case 3: return this.w; - default: throw new Error( "index is out of range: " + index ); + default: return THREE.onerror( 'index is out of range: ' + index ); } @@ -5176,7 +5249,7 @@ THREE.Vector4.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector4\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + THREE.onwarning( 'DEPRECATED: Vector4\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } @@ -5216,7 +5289,7 @@ THREE.Vector4.prototype = { if ( w !== undefined ) { - console.warn( 'DEPRECATED: Vector4\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + THREE.onwarning( 'DEPRECATED: Vector4\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } @@ -5254,6 +5327,8 @@ THREE.Vector4.prototype = { applyMatrix4: function ( m ) { + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); + var x = this.x; var y = this.y; var z = this.z; @@ -5711,6 +5786,7 @@ THREE.Vector4.prototype = { } }; + /** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley @@ -5813,12 +5889,12 @@ THREE.Euler.prototype = { }, - copy: function ( euler ) { + setFromVector: function ( v, order ) { - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; + this._x = v.x; + this._y = v.y; + this._z = v.z; + this._order = order || this._order; this._updateQuaternion(); @@ -5826,20 +5902,22 @@ THREE.Euler.prototype = { }, - setFromVector: function( v, order ) { + copy: function ( euler ) { - this._x = v.x; - this._y = v.y; - this._z = v.z; - this._order = order || this._order; + this._x = euler._x; + this._y = euler._y; + this._z = euler._z; + this._order = euler._order; this._updateQuaternion(); return this; - + }, - setFromRotationMatrix: function ( m, order ) { + setFromRotationMatrix: function ( m, order, update ) { + + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) @@ -5956,88 +6034,32 @@ THREE.Euler.prototype = { } else { - console.warn( 'WARNING: Euler.setFromRotationMatrix() given unsupported order: ' + order ) + THREE.onwarning( 'WARNING: Euler.setFromRotationMatrix() given unsupported order: ' + order ) } this._order = order; - this._updateQuaternion(); + if ( update !== false ) this._updateQuaternion(); return this; }, - setFromQuaternion: function ( q, order, update ) { - - // q is assumed to be normalized - - // clamp, to handle numerical problems - - function clamp( x ) { - - return Math.min( Math.max( x, -1 ), 1 ); - - } - - // http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m - - var sqx = q.x * q.x; - var sqy = q.y * q.y; - var sqz = q.z * q.z; - var sqw = q.w * q.w; - - order = order || this._order; - - if ( order === 'XYZ' ) { - - this._x = Math.atan2( 2 * ( q.x * q.w - q.y * q.z ), ( sqw - sqx - sqy + sqz ) ); - this._y = Math.asin( clamp( 2 * ( q.x * q.z + q.y * q.w ) ) ); - this._z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw + sqx - sqy - sqz ) ); - - } else if ( order === 'YXZ' ) { - - this._x = Math.asin( clamp( 2 * ( q.x * q.w - q.y * q.z ) ) ); - this._y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw - sqx - sqy + sqz ) ); - this._z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw - sqx + sqy - sqz ) ); - - } else if ( order === 'ZXY' ) { - - this._x = Math.asin( clamp( 2 * ( q.x * q.w + q.y * q.z ) ) ); - this._y = Math.atan2( 2 * ( q.y * q.w - q.z * q.x ), ( sqw - sqx - sqy + sqz ) ); - this._z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw - sqx + sqy - sqz ) ); - - } else if ( order === 'ZYX' ) { - - this._x = Math.atan2( 2 * ( q.x * q.w + q.z * q.y ), ( sqw - sqx - sqy + sqz ) ); - this._y = Math.asin( clamp( 2 * ( q.y * q.w - q.x * q.z ) ) ); - this._z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw + sqx - sqy - sqz ) ); - - } else if ( order === 'YZX' ) { - - this._x = Math.atan2( 2 * ( q.x * q.w - q.z * q.y ), ( sqw - sqx + sqy - sqz ) ); - this._y = Math.atan2( 2 * ( q.y * q.w - q.x * q.z ), ( sqw + sqx - sqy - sqz ) ); - this._z = Math.asin( clamp( 2 * ( q.x * q.y + q.z * q.w ) ) ); - - } else if ( order === 'XZY' ) { - - this._x = Math.atan2( 2 * ( q.x * q.w + q.y * q.z ), ( sqw - sqx + sqy - sqz ) ); - this._y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw + sqx - sqy - sqz ) ); - this._z = Math.asin( clamp( 2 * ( q.z * q.w - q.x * q.y ) ) ); - - } else { - - console.warn( 'WARNING: Euler.setFromQuaternion() given unsupported order: ' + order ) - - } - - this._order = order; - - if ( update !== false ) this._updateQuaternion(); + setFromQuaternion: function() { - return this; + var mIntermediate = null; + + return function( q, order, update ) { + + mIntermediate = mIntermediate || new THREE.Matrix4(); + mIntermediate.makeRotationFromQuaternion( q ); + this.setFromRotationMatrix( mIntermediate, order, update ); + + return this; + }; - }, + }(), reorder: function () { @@ -6080,6 +6102,18 @@ THREE.Euler.prototype = { }, + + toVector3: function ( optionalResult ) { + + if( optionalResult ) { + return optionalResult.set( this._x, this._y, this._z ); + } + else { + return new THREE.Vector3( this._x, this._y, this._z ); + } + + }, + clone: function () { return new THREE.Euler( this._x, this._y, this._z, this._order ); @@ -6087,6 +6121,7 @@ THREE.Euler.prototype = { } }; + /** * @author bhouston / http://exocortex.com */ @@ -6213,6 +6248,7 @@ THREE.Line3.prototype = { } }; + /** * @author bhouston / http://exocortex.com */ @@ -6477,6 +6513,7 @@ THREE.Box2.prototype = { } }; + /** * @author bhouston / http://exocortex.com * @author WestLangley / http://github.com/WestLangley @@ -6856,6 +6893,7 @@ THREE.Box3.prototype = { } }; + /** * @author alteredq / http://alteredqualia.com/ * @author WestLangley / http://github.com/WestLangley @@ -6923,7 +6961,7 @@ THREE.Matrix3.prototype = { multiplyVector3: function ( vector ) { - console.warn( 'DEPRECATED: Matrix3\'s .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); + THREE.onwarning( 'DEPRECATED: Matrix3\'s .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); return vector.applyMatrix3( this ); }, @@ -6978,9 +7016,9 @@ THREE.Matrix3.prototype = { }, - getInverse: function ( matrix, throwOnInvertible ) { + getInverse: function ( matrix, errorOnInvertible ) { - // input: THREE.Matrix4 + if ( ! ( matrix instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', matrix ); // ( based on http://code.google.com/p/webgl-mjs/ ) var me = matrix.elements; @@ -7002,15 +7040,9 @@ THREE.Matrix3.prototype = { if ( det === 0 ) { - var msg = "Matrix3.getInverse(): can't invert matrix, determinant is 0"; - - if ( throwOnInvertible || false ) { + if ( errorOnInvertible === true ) { - throw new Error( msg ); - - } else { - - console.warn( msg ); + return THREE.onerror( "Matrix3.getInverse(): can't invert matrix, determinant is 0", this ); } @@ -7040,7 +7072,7 @@ THREE.Matrix3.prototype = { getNormalMatrix: function ( m ) { - // input: THREE.Matrix4 + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); this.getInverse( m ).transpose(); @@ -7101,6 +7133,7 @@ THREE.Matrix3.prototype = { } }; + /** * @author mrdoob / http://mrdoob.com/ * @author supereggbert / http://www.paulbrunt.co.uk/ @@ -7173,7 +7206,7 @@ THREE.Matrix4.prototype = { extractPosition: function ( m ) { - console.warn( 'DEPRECATED: Matrix4\'s .extractPosition() has been renamed to .copyPosition().' ); + THREE.onwarning( 'DEPRECATED: Matrix4\'s .extractPosition() has been renamed to .copyPosition().' ); return this.copyPosition( m ); }, @@ -7191,6 +7224,31 @@ THREE.Matrix4.prototype = { }, + extractBasis: function ( xAxis, yAxis, zAxis ) { + + var te = this.elements; + + xAxis.set( te[0], te[1], te[2] ); + yAxis.set( te[4], te[5], te[6] ); + zAxis.set( te[8], te[9], te[10] ); + + return this; + + }, + + makeBasis: function ( xAxis, yAxis, zAxis ) { + + this.identity(); + + var te = this.elements; + te.elements[0] = xAxis.x; te.elements[1] = xAxis.y; te.elements[2] = xAxis.z; + te.elements[4] = yAxis.x; te.elements[5] = yAxis.y; te.elements[6] = yAxis.z; + te.elements[8] = zAxis.x; te.elements[9] = zAxis.y; te.elements[10] = zAxis.z; + + return this; + + }, + extractRotation: function () { var v1 = new THREE.Vector3(); @@ -7224,11 +7282,7 @@ THREE.Matrix4.prototype = { makeRotationFromEuler: function ( euler ) { - if ( euler instanceof THREE.Euler === false ) { - - console.error( 'ERROR: Matrix\'s .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); - - } + if ( ! ( euler instanceof THREE.Euler ) ) return THREE.onerror( 'expecting a Euler', euler ); var te = this.elements; @@ -7352,7 +7406,7 @@ THREE.Matrix4.prototype = { setRotationFromQuaternion: function ( q ) { - console.warn( 'DEPRECATED: Matrix4\'s .setRotationFromQuaternion() has been deprecated in favor of makeRotationFromQuaternion. Please update your code.' ); + THREE.onwarning( 'DEPRECATED: Matrix4\'s .setRotationFromQuaternion() has been deprecated in favor of makeRotationFromQuaternion. Please update your code.' ); return this.makeRotationFromQuaternion( q ); @@ -7439,7 +7493,7 @@ THREE.Matrix4.prototype = { if ( n !== undefined ) { - console.warn( 'DEPRECATED: Matrix4\'s .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); + THREE.onwarning( 'DEPRECATED: Matrix4\'s .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); return this.multiplyMatrices( m, n ); } @@ -7448,8 +7502,40 @@ THREE.Matrix4.prototype = { }, + multiplyList: function ( listOfMatrices ) { + + for (var i = 0, il = listOfMatrices.length; i < il ; i++) { + this.multiplyMatrices( this, listOfMatrices[ i ] ); + } + + return this; + + }, + + multiplyMatricesList: function ( listOfMatrices ) { + + if( listOfMatrices.length > 0 ) { + + this.copy( listOfMatrices[0] ); + + this.multiplyList( listOfMatrices.slice( 1 ) ); + + } + else { + + this.identity(); + + } + + return this; + + }, + multiplyMatrices: function ( a, b ) { + if ( ! ( a instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', a ); + if ( ! ( b instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', b ); + var ae = a.elements; var be = b.elements; var te = this.elements; @@ -7518,14 +7604,14 @@ THREE.Matrix4.prototype = { multiplyVector3: function ( vector ) { - console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); + THREE.onwarning( 'DEPRECATED: Matrix4\'s .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); return vector.applyProjection( this ); }, multiplyVector4: function ( vector ) { - console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + THREE.onwarning( 'DEPRECATED: Matrix4\'s .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); return vector.applyMatrix4( this ); }, @@ -7558,7 +7644,7 @@ THREE.Matrix4.prototype = { rotateAxis: function ( v ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); + THREE.onwarning( 'DEPRECATED: Matrix4\'s .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); v.transformDirection( this ); @@ -7566,7 +7652,7 @@ THREE.Matrix4.prototype = { crossVector: function ( vector ) { - console.warn( 'DEPRECATED: Matrix4\'s .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + THREE.onwarning( 'DEPRECATED: Matrix4\'s .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); return vector.applyMatrix4( this ); }, @@ -7683,7 +7769,7 @@ THREE.Matrix4.prototype = { return function () { - console.warn( 'DEPRECATED: Matrix4\'s .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); + THREE.onwarning( 'DEPRECATED: Matrix4\'s .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); var te = this.elements; return v1.set( te[12], te[13], te[14] ); @@ -7704,7 +7790,9 @@ THREE.Matrix4.prototype = { }, - getInverse: function ( m, throwOnInvertible ) { + getInverse: function ( m, errorOnInvertible ) { + + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm var te = this.elements; @@ -7736,15 +7824,9 @@ THREE.Matrix4.prototype = { if ( det == 0 ) { - var msg = "Matrix4.getInverse(): can't invert matrix, determinant is 0"; + if ( errorOnInvertible === true ) { - if ( throwOnInvertible || false ) { - - throw new Error( msg ); - - } else { - - console.warn( msg ); + return THREE.onerror( "Matrix4.getInverse(): can't invert matrix, determinant is 0", this ); } @@ -7761,31 +7843,31 @@ THREE.Matrix4.prototype = { translate: function ( v ) { - console.warn( 'DEPRECATED: Matrix4\'s .translate() has been removed.'); + THREE.onerror( 'DEPRECATED: Matrix4\'s .translate() has been removed.'); }, rotateX: function ( angle ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateX() has been removed.'); + THREE.onerror( 'DEPRECATED: Matrix4\'s .rotateX() has been removed.'); }, rotateY: function ( angle ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateY() has been removed.'); + THREE.onerror( 'DEPRECATED: Matrix4\'s .rotateY() has been removed.'); }, rotateZ: function ( angle ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateZ() has been removed.'); + THREE.onerror( 'DEPRECATED: Matrix4\'s .rotateZ() has been removed.'); }, rotateByAxis: function ( axis, angle ) { - console.warn( 'DEPRECATED: Matrix4\'s .rotateByAxis() has been removed.'); + THREE.onerror( 'DEPRECATED: Matrix4\'s .rotateByAxis() has been removed.'); }, @@ -7919,6 +8001,36 @@ THREE.Matrix4.prototype = { }, + + makeShear: function ( vector3Shear, reverseStyle ) { + + var xy = vector3Shear.x; + var xz = vector3Shear.y; + var yz = vector3Shear.z; + + if ( reverseStyle ) { + + this.set( + 1, 0, 0, 0, + xy, 1, 0, 0, + xz, yz, 1, 0, + 0, 0, 0, 1 + ); + + } else { + // Maya style + this.set( + 1, xy, xz, 0, + 0, 1, yz, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ); + } + + return this; + + }, + compose: function ( position, quaternion, scale ) { this.makeRotationFromQuaternion( quaternion ); @@ -7984,7 +8096,7 @@ THREE.Matrix4.prototype = { }(), - makeFrustum: function ( left, right, bottom, top, near, far ) { + makeFrustum: function ( left, right, bottom, top, near, far, filmOffset, filmSize ) { var te = this.elements; var x = 2 * near / ( right - left ); @@ -8000,18 +8112,28 @@ THREE.Matrix4.prototype = { te[2] = 0; te[6] = 0; te[10] = c; te[14] = d; te[3] = 0; te[7] = 0; te[11] = - 1; te[15] = 0; + if( filmOffset && filmSize ) { + // shift principle point, details: http://ksimek.github.io/2013/08/13/intrinsic/ + if( filmSize.x !== 0 ) { + te[8] += 2 * filmOffset.x / filmSize.x; + } + if( filmSize.y !== 0 ) { + te[9] += 2 * filmOffset.y / filmSize.y; + } + } + return this; }, - makePerspective: function ( fov, aspect, near, far ) { + makePerspective: function ( fov, aspect, near, far, filmOffset, filmSize ) { var ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) ); var ymin = - ymax; var xmin = ymin * aspect; var xmax = ymax * aspect; - return this.makeFrustum( xmin, xmax, ymin, ymax, near, far ); + return this.makeFrustum( xmin, xmax, ymin, ymax, near, far, filmOffset, filmSize ); }, @@ -8072,6 +8194,7 @@ THREE.Matrix4.prototype = { } }; + /** * @author bhouston / http://exocortex.com */ @@ -8542,6 +8665,7 @@ THREE.Ray.prototype = { } }; + /** * @author bhouston / http://exocortex.com * @author mrdoob / http://mrdoob.com/ @@ -8585,11 +8709,18 @@ THREE.Sphere.prototype = { } - var maxRadiusSq = 0; + var maxRadiusSq = 0, cx = center.x, cy = center.y, cz = center.z; for ( var i = 0, il = points.length; i < il; i ++ ) { - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); + var pt = points[ i ]; + var dx = cx - pt.x; + var dy = cy - pt.y; + var dz = cz - pt.z; + + var distanceSquared = dx * dx + dy * dy + dz * dz; + + maxRadiusSq = Math.max( maxRadiusSq, distanceSquared ); } @@ -8695,6 +8826,7 @@ THREE.Sphere.prototype = { } }; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -8873,6 +9005,7 @@ THREE.Frustum.prototype = { } }; + /** * @author bhouston / http://exocortex.com */ @@ -9059,6 +9192,8 @@ THREE.Plane.prototype = { return function ( matrix, optionalNormalMatrix ) { + if ( ! ( matrix instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', matrix ); + // compute new normal based on theory here: // http://www.songho.ca/opengl/gl_normaltransform.html var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); @@ -9096,6 +9231,7 @@ THREE.Plane.prototype = { } }; + /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ @@ -9104,6 +9240,8 @@ THREE.Plane.prototype = { THREE.Math = { PI2: Math.PI * 2, + DegreeToRadiansFactor: Math.PI / 180, + RadianToDegreesFactor: 180 / Math.PI, generateUUID: function () { @@ -9228,35 +9366,24 @@ THREE.Math = { }, - degToRad: function() { - - var degreeToRadiansFactor = Math.PI / 180; - - return function ( degrees ) { - - return degrees * degreeToRadiansFactor; - - }; - - }(), - - radToDeg: function() { + degToRad: function ( degrees ) { - var radianToDegreesFactor = 180 / Math.PI; + return degrees * this.DegreeToRadiansFactor; - return function ( radians ) { + }, - return radians * radianToDegreesFactor; + radToDeg: function ( radians ) { - }; + return radians * this.RadianToDegreesFactor; - }(), + }, isPowerOfTwo: function ( value ) { return ( value & ( value - 1 ) ) === 0 && value !== 0; } }; + /** * Spline from Tween.js, slightly optimized (and trashed) * http://sole.github.com/tween.js/examples/05_spline.html @@ -9433,6 +9560,7 @@ THREE.Spline = function ( points ) { }; }; + /** * @author bhouston / http://exocortex.com * @author mrdoob / http://mrdoob.com/ @@ -9623,26 +9751,28 @@ THREE.Triangle.prototype = { } }; + /** * @author mrdoob / http://mrdoob.com/ */ THREE.Vertex = function ( v ) { - console.warn( 'THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.') - return v; + return THREE.onerror( 'THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.' ); }; + /** * @author mrdoob / http://mrdoob.com/ */ THREE.UV = function ( u, v ) { - console.warn( 'THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.') + THREE.onerror( 'THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.') return new THREE.Vector2( u, v ); }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -9715,6 +9845,7 @@ THREE.Clock.prototype = { } }; + /** * https://github.com/mrdoob/eventdispatcher.js/ */ @@ -9827,6 +9958,7 @@ THREE.EventDispatcher.prototype = { }() }; + /** * @author mrdoob / http://mrdoob.com/ * @author bhouston / http://exocortex.com/ @@ -10287,6 +10419,7 @@ THREE.EventDispatcher.prototype = { }; }( THREE ) ); + /** * @author mrdoob / http://mrdoob.com/ * @author mikael emtinger / http://gomo.se/ @@ -10298,6 +10431,7 @@ THREE.Object3D = function () { this.id = THREE.Object3DIdCount ++; this.uuid = THREE.Math.generateUUID(); + this.className = "Object3D"; this.name = ''; @@ -10370,7 +10504,7 @@ THREE.Object3D.prototype = { get eulerOrder () { - console.warn( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); + THREE.onwarning( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); return this.rotation.order; @@ -10378,7 +10512,7 @@ THREE.Object3D.prototype = { set eulerOrder ( value ) { - console.warn( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); + THREE.onwarning( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); this.rotation.order = value; @@ -10386,13 +10520,13 @@ THREE.Object3D.prototype = { get useQuaternion () { - console.warn( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); + THREE.onwarning( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); }, set useQuaternion ( value ) { - console.warn( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); + THREE.onwarning( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); }, @@ -10512,7 +10646,7 @@ THREE.Object3D.prototype = { translate: function ( distance, axis ) { - console.warn( 'DEPRECATED: Object3D\'s .translate() has been removed. Use .translateOnAxis( axis, distance ) instead. Note args have been changed.' ); + THREE.onwarning( 'DEPRECATED: Object3D\'s .translate() has been removed. Use .translateOnAxis( axis, distance ) instead. Note args have been changed.' ); return this.translateOnAxis( axis, distance ); }, @@ -10591,7 +10725,7 @@ THREE.Object3D.prototype = { if ( object === this ) { - console.warn( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' ); + THREE.onwarning( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' ); return; } @@ -10734,7 +10868,7 @@ THREE.Object3D.prototype = { getChildByName: function ( name, recursive ) { - console.warn( 'DEPRECATED: Object3D\'s .getChildByName() has been renamed to .getObjectByName().' ); + THREE.onwarning( 'DEPRECATED: Object3D\'s .getChildByName() has been renamed to .getObjectByName().' ); return this.getObjectByName( name, recursive ); }, @@ -10847,6 +10981,7 @@ THREE.Object3D.prototype = { THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype ); THREE.Object3DIdCount = 0; + /** * @author mrdoob / http://mrdoob.com/ * @author supereggbert / http://www.paulbrunt.co.uk/ @@ -11679,6 +11814,7 @@ THREE.Projector = function () { } }; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -11728,17 +11864,19 @@ THREE.Face3.prototype = { } }; + /** * @author mrdoob / http://mrdoob.com/ */ THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { - console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.') + THREE.onwarning( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.') return new THREE.Face3( a, b, c, normal, color, materialIndex ); }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -11747,7 +11885,7 @@ THREE.BufferGeometry = function () { this.id = THREE.GeometryIdCount ++; this.uuid = THREE.Math.generateUUID(); - + this.className = "BufferGeometry"; this.name = ''; // attributes @@ -12102,7 +12240,7 @@ THREE.BufferGeometry.prototype = { this.attributes[ "normal" ] === undefined || this.attributes[ "uv" ] === undefined ) { - console.warn( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" ); + THREE.onwarning( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" ); return; } @@ -12513,6 +12651,7 @@ THREE.BufferGeometry.prototype = { }; THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype ); + /** * @author mrdoob / http://mrdoob.com/ * @author kile / http://kile.stravaganza.org/ @@ -12526,6 +12665,7 @@ THREE.Geometry = function () { this.id = THREE.GeometryIdCount ++; this.uuid = THREE.Math.generateUUID(); + this.className = "Geometry"; this.name = ''; @@ -12548,7 +12688,7 @@ THREE.Geometry = function () { this.boundingBox = null; this.boundingSphere = null; - this.hasTangents = false; + this.hasTangents = true; this.dynamic = true; // the intermediate typed arrays will be deleted when set to false @@ -13182,6 +13322,20 @@ THREE.Geometry.prototype = { } + geometry.morphTargets = this.morphTargets.slice( 0 ); + geometry.morphColors = this.morphColors.slice( 0 ); + geometry.morphNormals = this.morphNormals.slice( 0 ); + geometry.skinWeights = this.skinWeights.slice( 0 ); + geometry.skinIndices = this.skinIndices.slice( 0 ); + geometry.lineDistances = this.lineDistances.slice( 0 ); + + if( this.boundingBox ) geometry.boundingBox = this.boundingBox.clone(); + if( this.boundingSphere ) geometry.boundingSphere = this.boundingSphere.clone(); + + geometry.hasTangents = this.hasTangents; + + geometry.dynamic = this.dynamic; // the intermediate typed arrays will be deleted when set to false + return geometry; }, @@ -13197,6 +13351,7 @@ THREE.Geometry.prototype = { THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype ); THREE.GeometryIdCount = 0; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -13204,6 +13359,7 @@ THREE.GeometryIdCount = 0; THREE.Geometry2 = function ( size ) { THREE.BufferGeometry.call( this ); + this.className = "Geometry2"; this.vertices = this.addAttribute( 'position', Float32Array, size, 3 ).array; this.normals = this.addAttribute( 'normal', Float32Array, size, 3 ).array; @@ -13214,7 +13370,8 @@ THREE.Geometry2 = function ( size ) { }; -THREE.Geometry2.prototype = Object.create( THREE.BufferGeometry.prototype );/** +THREE.Geometry2.prototype = Object.create( THREE.BufferGeometry.prototype ); +/** * @author mrdoob / http://mrdoob.com/ * @author mikael emtinger / http://gomo.se/ * @author WestLangley / http://github.com/WestLangley @@ -13227,6 +13384,7 @@ THREE.Camera = function () { this.matrixWorldInverse = new THREE.Matrix4(); this.projectionMatrix = new THREE.Matrix4(); + this.normalizedViewport = { x: 0, y: 0, width: 1.0, height: 1.0 }; }; THREE.Camera.prototype = Object.create( THREE.Object3D.prototype ); @@ -13256,8 +13414,16 @@ THREE.Camera.prototype.clone = function (camera) { camera.matrixWorldInverse.copy( this.matrixWorldInverse ); camera.projectionMatrix.copy( this.projectionMatrix ); + camera.normalizedViewport = { + x: this.normalizedViewport.x, + y: this.normalizedViewport.y, + width: this.normalizedViewport.width, + height: this.normalizedViewport.height + }; + return camera; }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -13284,6 +13450,14 @@ THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () { this.projectionMatrix.makeOrthographic( this.left, this.right, this.top, this.bottom, this.near, this.far ); + + + var viewportMatrix = new THREE.Matrix4(); + viewportMatrix.elements[0] *= this.normalizedViewport.width; + viewportMatrix.elements[1] *= this.normalizedViewport.height; + viewportMatrix.elements[12] += this.normalizedViewport.x; + viewportMatrix.elements[13] += this.normalizedViewport.y; + this.projectionMatrix = viewportMatrix.multiply( this.projectionMatrix ); }; THREE.OrthographicCamera.prototype.clone = function () { @@ -13302,13 +13476,14 @@ THREE.OrthographicCamera.prototype.clone = function () { return camera; }; + /** * @author mrdoob / http://mrdoob.com/ * @author greggman / http://games.greggman.com/ * @author zz85 / http://www.lab4games.net/zz85/blog */ -THREE.PerspectiveCamera = function ( fov, aspect, near, far ) { +THREE.PerspectiveCamera = function ( fov, aspect, near, far, filmSize, filmOffset ) { THREE.Camera.call( this ); @@ -13316,6 +13491,8 @@ THREE.PerspectiveCamera = function ( fov, aspect, near, far ) { this.aspect = aspect !== undefined ? aspect : 1; this.near = near !== undefined ? near : 0.1; this.far = far !== undefined ? far : 2000; + this.filmSize = filmSize !== undefined ? filmSize : new THREE.Vector2( 1, 1 ); + this.filmOffset = filmOffset !== undefined ? filmOffset : new THREE.Vector2( 0, 0 ); this.updateProjectionMatrix(); @@ -13396,7 +13573,7 @@ THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { var aspect = this.fullWidth / this.fullHeight; var top = Math.tan( THREE.Math.degToRad( this.fov * 0.5 ) ) * this.near; - var bottom = -top; + var bottom = - top; var left = aspect * bottom; var right = aspect * top; var width = Math.abs( right - left ); @@ -13408,15 +13585,24 @@ THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { top - ( this.y + this.height ) * height / this.fullHeight, top - this.y * height / this.fullHeight, this.near, - this.far + this.far, + this.filmOffset, + this.filmSize ); } else { - this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far ); + this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far, this.filmOffset, this.filmSize ); } + var viewportMatrix = new THREE.Matrix4(); + viewportMatrix.elements[0] *= this.normalizedViewport.width; + viewportMatrix.elements[1] *= this.normalizedViewport.height; + viewportMatrix.elements[12] += this.normalizedViewport.x; + viewportMatrix.elements[13] += this.normalizedViewport.y; + this.projectionMatrix = viewportMatrix.multiply( this.projectionMatrix ); + }; THREE.PerspectiveCamera.prototype.clone = function () { @@ -13429,9 +13615,12 @@ THREE.PerspectiveCamera.prototype.clone = function () { camera.aspect = this.aspect; camera.near = this.near; camera.far = this.far; + camera.filmSize = this.filmSize; + camera.filmOffset = this.filmOffset; return camera; }; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -13458,6 +13647,7 @@ THREE.Light.prototype.clone = function ( light ) { return light; }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -13479,31 +13669,53 @@ THREE.AmbientLight.prototype.clone = function () { return light; }; + /** + * @author bhouston / http://clara.io/ * @author MPanknin / http://www.redplant.de/ * @author alteredq / http://alteredqualia.com/ */ -THREE.AreaLight = function ( color, intensity ) { +THREE.AreaLight = function ( color, intensity, distance, decayExponent, physicalFalloff ) { THREE.Light.call( this, color ); - this.normal = new THREE.Vector3( 0, -1, 0 ); - this.right = new THREE.Vector3( 1, 0, 0 ); + this.position.set( 0, 1, 0 ); + this.target = new THREE.Object3D(); this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.distance = ( distance !== undefined ) ? distance : 0; + this.decayExponent = ( decayExponent !== undefined ) ? decayExponent : 0; // for physically correct lights, should be 2. + this.physicalFalloff = ( physicalFalloff !== undefined ) ? physicalFalloff : false; this.width = 1.0; this.height = 1.0; - this.constantAttenuation = 1.5; - this.linearAttenuation = 0.5; - this.quadraticAttenuation = 0.1; - + // TODO: implement shadow maps. -bhouston, Oct 15, 2014 }; THREE.AreaLight.prototype = Object.create( THREE.Light.prototype ); +THREE.AreaLight.prototype.clone = function () { + + var light = new THREE.AreaLight(); + + THREE.Light.prototype.clone.call( this, light ); + + light.target = this.target.clone(); + + light.intensity = this.intensity; + light.distance = this.distance; + light.decayExponent = this.decayExponent; + light.physicalFalloff = this.physicalFalloff; + + light.width = this.width; + light.height = this.height; + + return light; + +}; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -13582,6 +13794,7 @@ THREE.DirectionalLight.prototype.clone = function () { return light; }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -13611,17 +13824,19 @@ THREE.HemisphereLight.prototype.clone = function () { return light; }; + /** * @author mrdoob / http://mrdoob.com/ */ -THREE.PointLight = function ( color, intensity, distance ) { +THREE.PointLight = function ( color, intensity, distance, decayExponent, physicalFalloff ) { THREE.Light.call( this, color ); this.intensity = ( intensity !== undefined ) ? intensity : 1; this.distance = ( distance !== undefined ) ? distance : 0; - + this.decayExponent = ( decayExponent !== undefined ) ? decayExponent : 0;; // for physically correct lights, should be 2. + this.physicalFalloff = ( physicalFalloff !== undefined ) ? physicalFalloff : false; }; THREE.PointLight.prototype = Object.create( THREE.Light.prototype ); @@ -13634,15 +13849,18 @@ THREE.PointLight.prototype.clone = function () { light.intensity = this.intensity; light.distance = this.distance; + light.decayExponent = this.decayExponent; + light.physicalFalloff = this.physicalFalloff; return light; }; + /** * @author alteredq / http://alteredqualia.com/ */ -THREE.SpotLight = function ( color, intensity, distance, angle, exponent ) { +THREE.SpotLight = function ( color, intensity, distance, angle, exponent, decayExponent, physicalFalloff ) { THREE.Light.call( this, color ); @@ -13651,6 +13869,9 @@ THREE.SpotLight = function ( color, intensity, distance, angle, exponent ) { this.intensity = ( intensity !== undefined ) ? intensity : 1; this.distance = ( distance !== undefined ) ? distance : 0; + this.decayExponent = ( decayExponent !== undefined ) ? decayExponent : 0;; // for physically correct lights, should be 2. + this.physicalFalloff = ( physicalFalloff !== undefined ) ? physicalFalloff : false; + this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; this.exponent = ( exponent !== undefined ) ? exponent : 10; @@ -13694,6 +13915,8 @@ THREE.SpotLight.prototype.clone = function () { light.distance = this.distance; light.angle = this.angle; light.exponent = this.exponent; + light.decayExponent = this.decayExponent; + light.physicalFalloff = this.physicalFalloff; light.castShadow = this.castShadow; light.onlyShadow = this.onlyShadow; @@ -13701,6 +13924,7 @@ THREE.SpotLight.prototype.clone = function () { return light; }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -13932,6 +14156,7 @@ THREE.Loader.prototype = { if ( shading === "phong" ) mtype = "MeshPhongMaterial"; else if ( shading === "basic" ) mtype = "MeshBasicMaterial"; + else if ( shading === "physical" ) mtype = "MeshPhysicalMaterial"; } @@ -14147,6 +14372,7 @@ THREE.Loader.prototype = { } }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -14213,6 +14439,7 @@ THREE.XHRLoader.prototype = { } }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -14280,6 +14507,7 @@ THREE.ImageLoader.prototype = { } } + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -14326,7 +14554,7 @@ THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, tex if ( json.metadata.type === 'scene' ) { - console.error( 'THREE.JSONLoader: "' + url + '" seems to be a Scene. Use THREE.SceneLoader instead.' ); + THREE.onerror( 'THREE.JSONLoader: "' + url + '" seems to be a Scene. Use THREE.SceneLoader instead.' ); return; } @@ -14336,7 +14564,7 @@ THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, tex } else { - console.error( 'THREE.JSONLoader: "' + url + '" seems to be unreachable or the file is empty.' ); + THREE.onerror( 'THREE.JSONLoader: "' + url + '" seems to be unreachable or the file is empty.' ); } @@ -14348,7 +14576,7 @@ THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, tex } else { - console.error( 'THREE.JSONLoader: Couldn\'t load "' + url + '" (' + xhr.status + ')' ); + THREE.onerror( 'THREE.JSONLoader: Couldn\'t load "' + url + '" (' + xhr.status + ')' ); } @@ -14735,7 +14963,7 @@ THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { - console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + + THREE.onwarning( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); } @@ -14824,6 +15052,7 @@ THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { } }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -14865,6 +15094,7 @@ THREE.LoadingManager = function ( onLoad, onProgress, onError ) { }; THREE.DefaultLoadingManager = new THREE.LoadingManager(); + /** * @author mrdoob / http://mrdoob.com/ */ @@ -14938,6 +15168,7 @@ THREE.BufferGeometryLoader.prototype = { } }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -15000,6 +15231,7 @@ THREE.Geometry2Loader.prototype = { } }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -15042,6 +15274,19 @@ THREE.MaterialLoader.prototype = { if ( json.ambient !== undefined ) material.ambient.setHex( json.ambient ); if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); if ( json.specular !== undefined ) material.specular.setHex( json.specular ); + if ( json.falloff !== undefined ) material.falloff = json.falloff; + if ( json.falloffColor !== undefined ) material.falloffColor.setHex( json.falloffColor ); + if ( json.roughness !== undefined ) material.roughness = json.roughness; + if ( json.metallic !== undefined ) material.metallic = json.metallic; + if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat; + if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness; + if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy; + if ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation; + if ( json.translucency !== undefined ) material.translucency.setHex( json.translucency ); + if ( json.translucencyNormalAlpha !== undefined ) material.translucencyNormalAlpha = json.translucencyNormalAlpha; + if ( json.translucencyNormalPower !== undefined ) material.translucencyNormalPower = json.translucencyNormalPower; + if ( json.translucencyViewAlpha !== undefined ) material.translucencyViewAlpha = json.translucencyViewAlpha; + if ( json.translucencyViewPower !== undefined ) material.translucencyViewPower = json.translucencyViewPower; if ( json.shininess !== undefined ) material.shininess = json.shininess; if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; if ( json.blending !== undefined ) material.blending = json.blending; @@ -15065,6 +15310,7 @@ THREE.MaterialLoader.prototype = { } }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -15325,14 +15571,14 @@ THREE.ObjectLoader.prototype = { case 'PointLight': - object = new THREE.PointLight( data.color, data.intensity, data.distance ); - + object = new THREE.PointLight( data.color, data.intensity, data.distance, data.decay, data.physicalFalloff ); + break; case 'SpotLight': - object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent ); - + object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent, data.decay, data.physicalFalloff ); + break; case 'HemisphereLight': @@ -15341,6 +15587,14 @@ THREE.ObjectLoader.prototype = { break; + case 'AreaLight': + + object = new THREE.AreaLight( data.color, data.intensity, data.distance, data.decayExponent, data.decay, data.physicalFalloff ); + object.width = data.width || 1; + object.height = data.height || 1; + + break; + case 'Mesh': var geometry = geometries[ data.geometry ]; @@ -15348,13 +15602,13 @@ THREE.ObjectLoader.prototype = { if ( geometry === undefined ) { - console.error( 'THREE.ObjectLoader: Undefined geometry ' + data.geometry ); + THREE.onerror( 'THREE.ObjectLoader: Undefined geometry ' + data.geometry ); } if ( material === undefined ) { - console.error( 'THREE.ObjectLoader: Undefined material ' + data.material ); + THREE.onerror( 'THREE.ObjectLoader: Undefined material ' + data.material ); } @@ -15368,7 +15622,7 @@ THREE.ObjectLoader.prototype = { if ( material === undefined ) { - console.error( 'THREE.ObjectLoader: Undefined material ' + data.material ); + THREE.onerror( 'THREE.ObjectLoader: Undefined material ' + data.material ); } @@ -15418,6 +15672,7 @@ THREE.ObjectLoader.prototype = { }() }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -16656,6 +16911,7 @@ THREE.SceneLoader.prototype = { } } + /** * @author mrdoob / http://mrdoob.com/ */ @@ -16698,6 +16954,7 @@ THREE.TextureLoader.prototype = { } }; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -16752,7 +17009,7 @@ THREE.Material.prototype = { if ( newValue === undefined ) { - console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); + THREE.onwarning( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); continue; } @@ -16831,6 +17088,7 @@ THREE.Material.prototype = { THREE.EventDispatcher.prototype.apply( THREE.Material.prototype ); THREE.MaterialIdCount = 0; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -16892,6 +17150,7 @@ THREE.LineBasicMaterial.prototype.clone = function () { return material; }; + /** * @author alteredq / http://alteredqualia.com/ * @@ -16958,6 +17217,7 @@ THREE.LineDashedMaterial.prototype.clone = function () { return material; }; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -17066,6 +17326,7 @@ THREE.MeshBasicMaterial.prototype.clone = function () { return material; }; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -17190,6 +17451,7 @@ THREE.MeshLambertMaterial.prototype.clone = function () { return material; }; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -17242,19 +17504,19 @@ THREE.MeshPhongMaterial = function ( parameters ) { THREE.Material.call( this ); this.color = new THREE.Color( 0xffffff ); // diffuse - this.ambient = new THREE.Color( 0xffffff ); + this.ambient = new THREE.Color( 0x000000 ); this.emissive = new THREE.Color( 0x000000 ); - this.specular = new THREE.Color( 0x111111 ); + this.specular = new THREE.Color( 0xffffff ); this.shininess = 30; - this.metal = false; - this.wrapAround = false; this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); this.map = null; + this.opacityMap = null; this.lightMap = null; + this.emissiveMap = null; this.bumpMap = null; this.bumpScale = 1; @@ -17302,14 +17564,14 @@ THREE.MeshPhongMaterial.prototype.clone = function () { material.specular.copy( this.specular ); material.shininess = this.shininess; - material.metal = this.metal; - material.wrapAround = this.wrapAround; material.wrapRGB.copy( this.wrapRGB ); material.map = this.map; + material.opacityMap = this.opacityMap; material.lightMap = this.lightMap; + material.emissiveMap = this.emissiveMap; material.bumpMap = this.bumpMap; material.bumpScale = this.bumpScale; @@ -17342,6 +17604,156 @@ THREE.MeshPhongMaterial.prototype.clone = function () { return material; }; + +/** + * + * @author bhouston / http://clara.io/ + * + */ + +THREE.MeshPhysicalMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); // diffuse + this.map = null; + this.opacityMap = null; + this.fog = true; + + this.falloff = false; + this.falloffColor = new THREE.Color( 0xffffff ); + this.falloffMap = null; + this.falloffBlendParams = new THREE.Vector4( 1.0, 0.0, 0.0, 1.0 ); + + this.specular = new THREE.Color( 0xffffff ); + this.specularMap = null; + + this.roughness = 0.5; + this.roughnessMap = null; + + this.metallic = 0.0; + this.metallicMap = null; + + this.clearCoat = 0.0; // 0 means no clear coat, 1 means complete clear coat. + this.clearCoatRoughness = 0.2; + + this.anisotropy = 0.0; // valid range is [-1,1].-1 is max vertical elongation, 0 is normal, +1 is max horizontal elongation + this.anisotropyMap = null; // only R is read and considered to be anisotropy. To get negative values, use texture brightness, gain + this.anisotropyRotation = 0.0; // converted to radias via multiplication by 2*PI. Thus the range [ 0 - 1 ] maps to radian [0, PI]. + this.anisotropyRotationMap = null; // only R is read and considered to be anisotropyRotation. + + this.translucency = new THREE.Color( 0x000000 ); + this.translucencyMap = null; + this.translucencyNormalAlpha = 0.75; + this.translucencyNormalPower = 1.0; + this.translucencyViewPower = 2.0; + this.translucencyViewAlpha = 0.75; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalScale = new THREE.Vector2( 1, 1 ); + + this.emissive = new THREE.Color( 0x000000 ); + this.emissiveMap = null; // given off arbitrarily by the object in all directions. Basically GI. + + this.ambient = new THREE.Color( 0x000000 ); + this.lightMap = null; // incoming light + + this.envMap = null; // Incoming environmental light. + this.diffuseEnvMap = null; // irradiance light. + + this.combine = THREE.AddOperation; + + this.shading = THREE.SmoothShading + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.blending = THREE.CustomBlending; + this.blendSrc = THREE.OneFactor; // output of shader must be premultiplied + this.blendDst = THREE.OneMinusSrcAlphaFactor; + this.blendEquation = THREE.AddEquation; + + this.vertexColors = THREE.NoColors; + + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; + + this.setValues( parameters ); +}; + +THREE.MeshPhysicalMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshPhysicalMaterial.prototype.clone = function () { + + var material = new THREE.MeshPhysicalMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.map = this.map; + material.opacityMap = this.opacityMap; + material.fog = this.fog; + + material.falloff = this.falloff; + material.falloffColor.copy( this.falloffColor ); + material.falloffMap = this.falloffMap; + material.falloffBlendParams.copy( this.falloffBlendParams ); + + material.specular.copy( this.specular ); + material.specularMap = this.specularMap; + + material.roughness = this.roughness; + material.roughnessMap = this.roughnessMap; + material.metallic = this.metallic; + material.metallicMap = this.metallicMap; + + material.shading = this.shading; + + material.translucency.copy( this.translucency ); + material.translucencyMap = this.translucencyMap; + material.translucencyNormalAlpha = this.translucencyNormalAlpha; + material.translucencyNormalPower = this.translucencyNormalPower; + material.translucencyViewPower = this.translucencyViewPower; + material.translucencyViewAlpha = this.translucencyViewAlpha; + + material.bumpMap = this.bumpMap; + material.bumpScale = this.bumpScale; + + material.normalMap = this.normalMap; + material.normalScale.copy( this.normalScale ); + + material.emissive.copy( this.emissive ); + material.emissiveMap = this.emissiveMap; + + material.ambient.copy( this.ambient ); + material.lightMap = this.lightMap; + + material.envMap = this.envMap; + material.diffuseEnvMap = this.diffuseEnvMap; + + material.combine = this.combine; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; + + return material; + +}; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -17383,6 +17795,7 @@ THREE.MeshDepthMaterial.prototype.clone = function () { return material; }; + /** * @author mrdoob / http://mrdoob.com/ * @@ -17430,6 +17843,7 @@ THREE.MeshNormalMaterial.prototype.clone = function () { return material; }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -17453,6 +17867,7 @@ THREE.MeshFaceMaterial.prototype.clone = function () { return material; }; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -17519,6 +17934,7 @@ THREE.ParticleSystemMaterial.prototype.clone = function () { // backwards compatibility THREE.ParticleBasicMaterial = THREE.ParticleSystemMaterial; + /** * @author alteredq / http://alteredqualia.com/ * @@ -17554,6 +17970,7 @@ THREE.ShaderMaterial = function ( parameters ) { THREE.Material.call( this ); + this.shaderID = null; this.fragmentShader = "void main() {}"; this.vertexShader = "void main() {}"; this.uniforms = {}; @@ -17629,6 +18046,7 @@ THREE.ShaderMaterial.prototype.clone = function () { return material; }; + /** * @author alteredq / http://alteredqualia.com/ * @@ -17685,6 +18103,7 @@ THREE.SpriteMaterial.prototype.clone = function () { return material; }; + /** * @author mrdoob / http://mrdoob.com/ * @@ -17724,10 +18143,12 @@ THREE.SpriteCanvasMaterial.prototype.clone = function () { // backwards compatibility -THREE.ParticleCanvasMaterial = THREE.SpriteCanvasMaterial;/** +THREE.ParticleCanvasMaterial = THREE.SpriteCanvasMaterial; +/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author szimek / https://github.com/szimek/ + * @author bhouston / https://clara.io/ */ THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { @@ -17756,6 +18177,15 @@ THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, f this.offset = new THREE.Vector2( 0, 0 ); this.repeat = new THREE.Vector2( 1, 1 ); + // formula used + // x' = ( x - gainPivot ) * gain + brightness + gainPivot + // for standard contrast adjust, set gain to contrast, and gainPivot to 0.5 + this.invert = false; + this.gainPivot = 0.0; + this.gain = 1.0; + this.brightness = 0.0; + this.encoding = THREE.sRGB; + this.generateMipmaps = true; this.premultiplyAlpha = false; this.flipY = true; @@ -17807,6 +18237,12 @@ THREE.Texture.prototype = { texture.offset.copy( this.offset ); texture.repeat.copy( this.repeat ); + texture.invert = this.invert; + texture.gainPivot = this.gainPivot; + texture.gain = this.gain; + texture.brightness = this.brightness; + texture.encoding = this.encoding; + texture.generateMipmaps = this.generateMipmaps; texture.premultiplyAlpha = this.premultiplyAlpha; texture.flipY = this.flipY; @@ -17833,6 +18269,7 @@ THREE.Texture.prototype = { THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype ); THREE.TextureIdCount = 0; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -17859,6 +18296,7 @@ THREE.CompressedTexture.prototype.clone = function () { return texture; }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -17882,6 +18320,7 @@ THREE.DataTexture.prototype.clone = function () { return texture; }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -17911,6 +18350,7 @@ THREE.ParticleSystem.prototype.clone = function ( object ) { return object; }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -17940,6 +18380,7 @@ THREE.Line.prototype.clone = function ( object ) { return object; }; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -17988,7 +18429,7 @@ THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { } - console.log( "THREE.Mesh.getMorphTargetIndexByName: morph target " + name + " does not exist. Returning 0." ); + THREE.onwarning( "THREE.Mesh.getMorphTargetIndexByName: morph target " + name + " does not exist. Returning 0." ); return 0; @@ -18003,6 +18444,7 @@ THREE.Mesh.prototype.clone = function ( object ) { return object; }; + /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ @@ -18060,6 +18502,7 @@ THREE.Bone.prototype.update = function ( parentSkinMatrix, forceUpdate ) { }; + /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ @@ -18329,6 +18772,7 @@ THREE.SkinnedMesh.prototype.clone = function ( object ) { return object; }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -18437,7 +18881,7 @@ THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) { } else { - console.warn( "animation[" + label + "] undefined" ); + THREE.onwarning( "animation[" + label + "] undefined" ); } @@ -18525,6 +18969,7 @@ THREE.MorphAnimMesh.prototype.clone = function ( object ) { return object; }; + /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ @@ -18637,6 +19082,7 @@ THREE.LOD.prototype.clone = function ( object ) { return object; }; + /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ @@ -18684,7 +19130,8 @@ THREE.Sprite.prototype.clone = function ( object ) { // Backwards compatibility -THREE.Particle = THREE.Sprite;/** +THREE.Particle = THREE.Sprite; +/** * @author mrdoob / http://mrdoob.com/ */ @@ -18814,6 +19261,7 @@ THREE.Scene.prototype.clone = function ( object ) { return object; }; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -18835,6 +19283,7 @@ THREE.Fog.prototype.clone = function () { return new THREE.Fog( this.color.getHex(), this.near, this.far ); }; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -18854,6 +19303,7 @@ THREE.FogExp2.prototype.clone = function () { return new THREE.FogExp2( this.color.getHex(), this.density ); }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -19051,7 +19501,7 @@ THREE.CanvasRenderer = function ( parameters ) { this.setClearColorHex = function ( hex, alpha ) { - console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); + THREE.onwarning( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); this.setClearColor( hex, alpha ); }; @@ -19114,7 +19564,7 @@ THREE.CanvasRenderer = function ( parameters ) { if ( camera instanceof THREE.Camera === false ) { - console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' ); + THREE.onerror( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' ); return; } @@ -19500,7 +19950,7 @@ THREE.CanvasRenderer = function ( parameters ) { drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y ); - if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) { + if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial || material instanceof THREE.MeshPhysicalMaterial ) && material.map === null ) { _diffuseColor.copy( material.color ); _emissiveColor.copy( material.emissive ); @@ -19978,18 +20428,93 @@ THREE.CanvasRenderer = function ( parameters ) { } }; + /** * Shader chunks for WebLG Shader library - * + * * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ * @author mikael emtinger / http://gomo.se/ + * @author bhouston / http://clara.io/ */ THREE.ShaderChunk = { // FOG + common: [ + + "#define PI 3.14159", + "#define PI2 6.28318", + "#define LOG2 1.442695", + "#define ENCODING_Linear 3000", + "#define ENCODING_sRGB 3001", + "#define ENCODING_RGBE 3002", + "#define ENCODING_RGBM7 3004", + "#define ENCODING_RGBM16 3005", + "#define SPECULAR_COEFF 0.18", + "float square( float a ) { return a*a; }", + "vec2 square( vec2 a ) { return vec2( a.x*a.x, a.y*a.y ); }", + "vec3 square( vec3 a ) { return vec3( a.x*a.x, a.y*a.y, a.z*a.z ); }", + "vec4 square( vec4 a ) { return vec4( a.x*a.x, a.y*a.y, a.z*a.z, a.w*a.w ); }", + "float saturate( float a ) { return clamp( a, 0.0, 1.0 ); }", + "vec2 saturate( vec2 a ) { return clamp( a, 0.0, 1.0 ); }", + "vec3 saturate( vec3 a ) { return clamp( a, 0.0, 1.0 ); }", + "vec4 saturate( vec4 a ) { return clamp( a, 0.0, 1.0 ); }", + "float average( float a ) { return a; }", + "float average( vec2 a ) { return ( a.x + a.y) * 0.5; }", + "float average( vec3 a ) { return ( a.x + a.y + a.z) * 0.3333333333; }", + "float average( vec4 a ) { return ( a.x + a.y + a.z + a.w) * 0.25; }", + "float whiteCompliment( float a ) { return saturate( 1.0 - a ); }", + "vec2 whiteCompliment( vec2 a ) { return saturate( vec2(1.0) - a ); }", + "vec3 whiteCompliment( vec3 a ) { return saturate( vec3(1.0) - a ); }", + "vec4 whiteCompliment( vec4 a ) { return saturate( vec4(1.0) - a ); }", + "vec3 projectOnPlane( vec3 point, vec3 pointOnPlane, vec3 planeNormal) {", + "float distance = dot( planeNormal, point-pointOnPlane );", + "return point - distance * planeNormal;", + "}", + "float sideOfPlane( vec3 point, vec3 pointOnPlane, vec3 planeNormal ) {", + "return sign( dot( point - pointOnPlane, planeNormal ) );", + "}", + "vec2 applyUVOffsetRepeat( vec2 uv, vec4 offsetRepeat ) {", + "return uv * offsetRepeat.zw + offsetRepeat.xy;", + "}", + "vec3 linePlaneIntersect( vec3 pointOnLine, vec3 lineDirection, vec3 pointOnPlane, vec3 planeNormal ) {", + "return pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) );", + "}", + "vec4 applyGainBrightness( vec4 texel, vec4 gainBrightnessCoeff ) {", + "if( gainBrightnessCoeff.w < 0.0 ) {", + "texel.xyz = whiteCompliment( texel.xyz );", + "}", + "texel.xyz = ( texel.xyz - vec3( gainBrightnessCoeff.x ) ) * gainBrightnessCoeff.y + vec3( gainBrightnessCoeff.z + gainBrightnessCoeff.x );", + "return texel;", + "}", + "vec4 texelDecode( vec4 texel, int encoding ) {", + + "if( encoding == 3001 ) {", // sRGB + "texel = vec4( pow( max( texel.xyz, vec3( 0.0 ) ), vec3( 2.2 ) ), texel.w );", + "}", + + "else if( encoding == 3002 ) {", // RGBE / Radiance + "texel = vec4( texel.xyz * pow( 2.0, texel.w*256.0 - 128.0 ), 1.0 );", + "}", + + // TODO LogLUV decoding. + + "else if( encoding == 3004 ) {", // RGBM 7.0 / Marmoset + "texel = vec4( texel.xyz * texel.w * 7.0, 1.0 );", + "}", + + "else if( encoding == 3005 ) {", // RGBM 16 + "texel = vec4( texel.xyz * texel.w * 16.0, 1.0 );", + "}", + + "return texel;", + "}", + ].join("\n"), + + // FOG + fog_pars_fragment: [ "#ifdef USE_FOG", @@ -20019,9 +20544,8 @@ THREE.ShaderChunk = { "#ifdef FOG_EXP2", - "const float LOG2 = 1.442695;", - "float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );", - "fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );", + "float fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );", + "fogFactor = 1.0 - saturate( fogFactor );", "#else", @@ -20035,61 +20559,53 @@ THREE.ShaderChunk = { ].join("\n"), - // ENVIRONMENT MAP - - envmap_pars_fragment: [ - - "#ifdef USE_ENVMAP", - - "uniform float reflectivity;", - "uniform samplerCube envMap;", - "uniform float flipEnvMap;", - "uniform int combine;", - - "#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )", + // DIFFUSE ENVIRONMENT MAP - "uniform bool useRefract;", - "uniform float refractionRatio;", + diffuseenvmap_pars_fragment: [ - "#else", - - "varying vec3 vReflect;", + "#if defined( USE_DIFFUSEENVMAP )", - "#endif", + "uniform samplerCube diffuseEnvMap;", + "uniform int diffuseEnvEncoding;", "#endif" ].join("\n"), - envmap_fragment: [ + // ENVIRONMENT MAP - "#ifdef USE_ENVMAP", + envmap_pars_fragment: [ - "vec3 reflectVec;", + "#if defined( USE_DIFFUSEENVMAP ) || defined( USE_ENVMAP )", - "#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )", + "uniform float flipEnvMap;", - "vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", + "#endif", - "if ( useRefract ) {", + "#ifdef USE_ENVMAP", - "reflectVec = refract( cameraToVertex, normal, refractionRatio );", + "uniform float reflectivity;", + "uniform samplerCube envMap;", + "uniform int combine;", + "uniform int envEncoding;", - "} else { ", + "#endif" - "reflectVec = reflect( cameraToVertex, normal );", + ].join("\n"), - "}", + envmap_fragment: [ - "#else", + "#if defined( USE_ENVMAP ) && ! defined( PHYSICAL )", - "reflectVec = vReflect;", + "vec3 worldNormal = vec3( normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz ) );", + "vec3 worldView = -vec3( normalize( ( vec4( viewDirection, 0.0 ) * viewMatrix ).xyz ) );", - "#endif", + "vec3 reflectVec = reflect( worldView, worldNormal );", "#ifdef DOUBLE_SIDED", "float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + "vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", "#else", @@ -20098,23 +20614,21 @@ THREE.ShaderChunk = { "#endif", - "#ifdef GAMMA_INPUT", - - "cubeColor.xyz *= cubeColor.xyz;", + "cubeColor = texelDecode( cubeColor, envEncoding );", - "#endif", + "float fresnelReflectivity = saturate( reflectivity );", "if ( combine == 1 ) {", - "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );", + "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, fresnelReflectivity );", "} else if ( combine == 2 ) {", - "gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;", + "gl_FragColor.xyz += cubeColor.xyz * fresnelReflectivity;", "} else {", - "gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );", + "gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, fresnelReflectivity );", "}", @@ -20122,19 +20636,6 @@ THREE.ShaderChunk = { ].join("\n"), - envmap_pars_vertex: [ - - "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )", - - "varying vec3 vReflect;", - - "uniform float refractionRatio;", - "uniform bool useRefract;", - - "#endif" - - ].join("\n"), - worldpos_vertex : [ "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )", @@ -20161,29 +20662,6 @@ THREE.ShaderChunk = { ].join("\n"), - envmap_vertex : [ - - "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )", - - "vec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;", - "worldNormal = normalize( worldNormal );", - - "vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );", - - "if ( useRefract ) {", - - "vReflect = refract( cameraToVertex, worldNormal, refractionRatio );", - - "} else {", - - "vReflect = reflect( cameraToVertex, worldNormal );", - - "}", - - "#endif" - - ].join("\n"), - // COLOR MAP (particles) map_particle_pars_fragment: [ @@ -20201,7 +20679,7 @@ THREE.ShaderChunk = { "#ifdef USE_MAP", - "gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );", + "gl_FragColor = gl_FragColor * texelDecode( texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) ), ENCODING_sRGB );", "#endif" @@ -20211,10 +20689,9 @@ THREE.ShaderChunk = { map_pars_vertex: [ - "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )", "varying vec2 vUv;", - "uniform vec4 offsetRepeat;", "#endif" @@ -20222,9 +20699,11 @@ THREE.ShaderChunk = { map_pars_fragment: [ - "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )", "varying vec2 vUv;", + "uniform vec4 offsetRepeat;", + "uniform vec4 gainBrightness;", "#endif", @@ -20238,9 +20717,9 @@ THREE.ShaderChunk = { map_vertex: [ - "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )", - "vUv = uv * offsetRepeat.zw + offsetRepeat.xy;", + "vUv = uv;", "#endif" @@ -20248,18 +20727,91 @@ THREE.ShaderChunk = { map_fragment: [ - "#ifdef USE_MAP", + "#if defined( USE_MAP ) || defined( USE_FALLOFFMAP )", - "vec4 texelColor = texture2D( map, vUv );", + "vec2 vUvLocal = applyUVOffsetRepeat( vUv, offsetRepeat );", - "#ifdef GAMMA_INPUT", + "#endif", - "texelColor.xyz *= texelColor.xyz;", + "#ifdef USE_MAP", - "#endif", + "vec4 texelColor = clamp( applyGainBrightness( texelDecode( texture2D( map, vUvLocal ), ENCODING_sRGB ), gainBrightness ), vec4(0.0), vec4(1.0) );", "gl_FragColor = gl_FragColor * texelColor;", + "#if defined( PHYSICAL ) || defined( PHONG )", + + "diffuseColor *= texelColor.xyz;", + + "#endif", // PHYSICAL + + "#endif" + + ].join("\n"), + + // FALLOFF MAP + + falloffmap_pars_fragment: [ + + "#ifdef USE_FALLOFFMAP", + + "uniform sampler2D falloffMap;", + + "#endif" + + ].join("\n"), + + // OPACITY MAP + + opacitymap_pars_fragment: [ + + "#ifdef USE_OPACITYMAP", + + "uniform sampler2D opacityMap;", + "uniform vec4 opacityOffsetRepeat;", + "uniform vec4 opacityGainBrightness;", + + "#endif" + + ].join("\n"), + + + opacitymap_fragment: [ + + "#ifdef USE_OPACITYMAP", + + "vec2 vOpacityUv = applyUVOffsetRepeat( vUv, opacityOffsetRepeat );", + "vec4 texelOpacity = applyGainBrightness( texture2D( opacityMap, vOpacityUv ), opacityGainBrightness );", + + "gl_FragColor.w = clamp( gl_FragColor.w * texelOpacity.r, 0.0, 1.0 );", + + "#endif" + + ].join("\n"), + + // TRANSLUCENCY MAP + + translucencymap_pars_fragment: [ + + "#ifdef USE_TRANSLUCENCYMAP", + + "uniform sampler2D translucencyMap;", + "uniform vec4 translucencyOffsetRepeat;", + "uniform vec4 translucencyGainBrightness;", + + "#endif" + + ].join("\n"), + + translucencymap_fragment: [ + + "#ifdef USE_TRANSLUCENCYMAP", + + "vec2 vTranslucencyUv = applyUVOffsetRepeat( vUv, translucencyOffsetRepeat );", + "vec4 texelTranslucency = applyGainBrightness( texture2D( translucencyMap, vTranslucencyUv ), translucencyGainBrightness );", + + "translucencyColor.xyz = clamp( translucencyColor.xyz * texelTranslucency.xyz, vec3( 0.0 ), vec3( 1.0 ) );", + "#endif" ].join("\n"), @@ -20268,18 +20820,29 @@ THREE.ShaderChunk = { lightmap_pars_fragment: [ - "#ifdef USE_LIGHTMAP", + "#if defined( USE_LIGHTMAP ) || defined( USE_EMISSIVEMAP )", "varying vec2 vUv2;", + + "#endif", + + "#if defined( USE_LIGHTMAP )", + "uniform sampler2D lightMap;", + "#endif", + + "#if defined( USE_EMISSIVEMAP )", + + "uniform sampler2D emissiveMap;", + "#endif" ].join("\n"), lightmap_pars_vertex: [ - "#ifdef USE_LIGHTMAP", + "#if defined( USE_LIGHTMAP ) || defined( USE_EMISSIVEMAP )", "varying vec2 vUv2;", @@ -20291,7 +20854,7 @@ THREE.ShaderChunk = { "#ifdef USE_LIGHTMAP", - "gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );", + //"gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );", "#endif" @@ -20299,7 +20862,7 @@ THREE.ShaderChunk = { lightmap_vertex: [ - "#ifdef USE_LIGHTMAP", + "#if defined( USE_LIGHTMAP ) || defined( USE_EMISSIVEMAP )", "vUv2 = uv2;", @@ -20307,6 +20870,7 @@ THREE.ShaderChunk = { ].join("\n"), + // BUMP MAP bumpmap_pars_fragment: [ @@ -20314,6 +20878,7 @@ THREE.ShaderChunk = { "#ifdef USE_BUMPMAP", "uniform sampler2D bumpMap;", + "uniform vec4 bumpOffsetRepeat;", "uniform float bumpScale;", // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen @@ -20323,30 +20888,48 @@ THREE.ShaderChunk = { "vec2 dHdxy_fwd() {", - "vec2 dSTdx = dFdx( vUv );", - "vec2 dSTdy = dFdy( vUv );", + "#ifdef GL_OES_standard_derivatives", + + "vec2 vBumpUv = applyUVOffsetRepeat( vUv, bumpOffsetRepeat );", + + "vec2 dSTdx = dFdx( vBumpUv );", + "vec2 dSTdy = dFdy( vBumpUv );", - "float Hll = bumpScale * texture2D( bumpMap, vUv ).x;", - "float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;", - "float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;", + "float Hll = bumpScale * texture2D( bumpMap, vBumpUv ).x;", + "float dBx = bumpScale * texture2D( bumpMap, vBumpUv + dSTdx ).x - Hll;", + "float dBy = bumpScale * texture2D( bumpMap, vBumpUv + dSTdy ).x - Hll;", - "return vec2( dBx, dBy );", + "return vec2( dBx, dBy );", + + "#else", + + "return vec2( 0.0, 0.0 );", + + "#endif", "}", "vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {", - "vec3 vSigmaX = dFdx( surf_pos );", - "vec3 vSigmaY = dFdy( surf_pos );", - "vec3 vN = surf_norm;", // normalized + "#ifdef GL_OES_standard_derivatives", + + "vec3 vSigmaX = dFdx( surf_pos );", + "vec3 vSigmaY = dFdy( surf_pos );", + "vec3 vN = surf_norm;", // normalized - "vec3 R1 = cross( vSigmaY, vN );", - "vec3 R2 = cross( vN, vSigmaX );", + "vec3 R1 = cross( vSigmaY, vN );", + "vec3 R2 = cross( vN, vSigmaX );", - "float fDet = dot( vSigmaX, R1 );", + "float fDet = dot( vSigmaX, R1 );", - "vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );", - "return normalize( abs( fDet ) * surf_norm - vGrad );", + "vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );", + "return normalize( abs( fDet ) * surf_norm - vGrad );", + + "#else", + + "return surf_norm;", + + "#endif", "}", @@ -20354,6 +20937,38 @@ THREE.ShaderChunk = { ].join("\n"), + // LIGHT ATTENUATION function + + lightattenuation_func_fragment: [ + + "float calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {", + "if ( decayExponent > 0.0 && cutoffDistance > 0.0 ) {", + "return pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );", + "}", + "else if ( decayExponent < 0.0 ) {", + // this is based upon UE4 light fall as described on page 11 of: + // https://de45xmedrsdbp.cloudfront.net/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf + "float numerator = 1.0;", + "if( cutoffDistance > 0.0 ) {", + "numerator = ( saturate( 1.0 - pow( lightDistance / cutoffDistance, 4.0 ) ) );", + "numerator *= numerator;", + "} ", + "return numerator / ( ( lightDistance * lightDistance ) + 1.0 );", + "}", + "else {", + "return 1.0;", + "}", + + /*"float distanceAttenuation = 1.0 / pow( max( lightDistance, 0.0 ), decayExponent );", + "if ( cutoffDistance > 0.0 ) {", + "distanceAttenuation *= 1.0 - min( lightDistance / cutoffDistance, 1.0 );", + "}", + "return distanceAttenuation;",*/ + "}", + + + ].join("\n"), + // NORMAL MAP normalmap_pars_fragment: [ @@ -20361,6 +20976,7 @@ THREE.ShaderChunk = { "#ifdef USE_NORMALMAP", "uniform sampler2D normalMap;", + "uniform vec4 normalOffsetRepeat;", "uniform vec2 normalScale;", // Per-Pixel Tangent Space Normal Mapping @@ -20368,19 +20984,29 @@ THREE.ShaderChunk = { "vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {", - "vec3 q0 = dFdx( eye_pos.xyz );", - "vec3 q1 = dFdy( eye_pos.xyz );", - "vec2 st0 = dFdx( vUv.st );", - "vec2 st1 = dFdy( vUv.st );", + "#ifdef GL_OES_standard_derivatives", + + "vec2 vNormalUv = applyUVOffsetRepeat( vUv, normalOffsetRepeat );", + + "vec3 q0 = dFdx( eye_pos.xyz );", + "vec3 q1 = dFdy( eye_pos.xyz );", + "vec2 st0 = dFdx( vNormalUv.st );", + "vec2 st1 = dFdy( vNormalUv.st );", + + "vec3 S = normalize( q0 * st1.t - q1 * st0.t );", + "vec3 T = normalize( -q0 * st1.s + q1 * st0.s );", + "vec3 N = normalize( surf_norm );", - "vec3 S = normalize( q0 * st1.t - q1 * st0.t );", - "vec3 T = normalize( -q0 * st1.s + q1 * st0.s );", - "vec3 N = normalize( surf_norm );", + "vec3 mapN = texture2D( normalMap, vNormalUv ).xyz * 2.0 - 1.0;", + "mapN.xy = normalScale * mapN.xy;", + "mat3 tsn = mat3( S, T, N );", + "return normalize( tsn * mapN );", - "vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;", - "mapN.xy = normalScale * mapN.xy;", - "mat3 tsn = mat3( S, T, N );", - "return normalize( tsn * mapN );", + "#else", + + "return surf_norm;", + + "#endif", "}", @@ -20388,6 +21014,138 @@ THREE.ShaderChunk = { ].join("\n"), + // ANISOTROPY MAP + + anisotropymap_pars_fragment: [ + + "#ifdef USE_ANISOTROPYMAP", + + "uniform sampler2D anisotropyMap;", + "uniform vec4 anisotropyGainBrightness;", + "uniform vec4 anisotropyOffsetRepeat;", + + "#endif" + ].join("\n"), + + anisotropymap_fragment: [ + + "#ifdef USE_ANISOTROPYMAP", + + "vec2 vAnisotropyUv = applyUVOffsetRepeat( vUv, anisotropyOffsetRepeat );", + + "#else", + + "#ifdef ANISOTROPY", + + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )", + + "vec2 vAnisotropyUv = vUv;", + + "#else", + + "vec2 vAnisotropyUv = vec2( 0, 0 );", + + "#endif", + + "#endif", + + "#endif", + + "float anisotropyStrength = anisotropy;", + + "#ifdef USE_ANISOTROPYMAP", + + "vec4 texelAnisotropy = applyGainBrightness( texture2D( anisotropyMap, vAnisotropyUv ), anisotropyGainBrightness );", + "anisotropyStrength = clamp( anisotropyStrength + texelAnisotropy.r, -1.0, 1.0 );", + + "#endif" + + ].join("\n"), + + // ANISOTROPY ROTATION MAP + + anisotropyrotationmap_pars_fragment: [ + + "#ifdef USE_ANISOTROPYROTATIONMAP", + + "uniform sampler2D anisotropyRotationMap;", + "uniform vec4 anisotropyRotationGainBrightness;", + "uniform vec4 anisotropyRotationOffsetRepeat;", + + "#endif" + + ].join("\n"), + + anisotropyrotationmap_fragment: [ + + "float anisotropyRotationStrength = anisotropyRotation;", + + "#ifdef USE_ANISOTROPYROTATIONMAP", + + "vec2 vAnisotropyRotationUv = applyUVOffsetRepeat( vUv, anisotropyRotationOffsetRepeat );", + "vec4 texelAnisotropyRotation = applyGainBrightness( texture2D( anisotropyRotationMap, vAnisotropyRotationUv ), anisotropyRotationGainBrightness );", + "anisotropyRotationStrength += texelAnisotropyRotation.r;", + + "#endif" + + ].join("\n"), + + // METALLIC MAP + + metallicmap_pars_fragment: [ + + "#ifdef USE_METALLICMAP", + + "uniform sampler2D metallicMap;", + "uniform vec4 metallicGainBrightness;", + "uniform vec4 metallicOffsetRepeat;", + + "#endif" + + ].join("\n"), + + metallicmap_fragment: [ + + "float metallicStrength = metallic;", + + "#ifdef USE_METALLICMAP", + + "vec2 vMetallicUv = applyUVOffsetRepeat( vUv, metallicOffsetRepeat );", + "vec4 texelMetallic = applyGainBrightness( texture2D( metallicMap, vMetallicUv ), metallicGainBrightness );", + "metallicStrength = clamp( metallicStrength * texelMetallic.r, 0.0, 1.0 );", + + "#endif" + + ].join("\n"), + + // ROUGHNESS MAP + + roughnessmap_pars_fragment: [ + + "#ifdef USE_ROUGHNESSMAP", + + "uniform sampler2D roughnessMap;", + "uniform vec4 roughnessOffsetRepeat;", + "uniform vec4 roughnessGainBrightness;", + + "#endif" + + ].join("\n"), + + roughnessmap_fragment: [ + + "float roughnessStrength = roughness;", + + "#ifdef USE_ROUGHNESSMAP", + + "vec2 vRoughnessUv = applyUVOffsetRepeat( vUv, roughnessOffsetRepeat );", + "vec4 texelRoughness = applyGainBrightness( texture2D( roughnessMap, vRoughnessUv ), roughnessGainBrightness );", + "roughnessStrength = clamp( roughnessStrength * texelRoughness.r, 0.0, 1.0 );", + + "#endif" + + ].join("\n"), + // SPECULAR MAP specularmap_pars_fragment: [ @@ -20395,6 +21153,8 @@ THREE.ShaderChunk = { "#ifdef USE_SPECULARMAP", "uniform sampler2D specularMap;", + "uniform vec4 specularGainBrightness;", + "uniform vec4 specularOffsetRepeat;", "#endif" @@ -20402,18 +21162,24 @@ THREE.ShaderChunk = { specularmap_fragment: [ - "float specularStrength;", + "#ifdef PHYSICAL", + "vec3 specularColor = specular;", + "#else", + "float specularStrength = 1.0;", + "#endif", "#ifdef USE_SPECULARMAP", - "vec4 texelSpecular = texture2D( specularMap, vUv );", - "specularStrength = texelSpecular.r;", + "vec2 vSpecularUv = applyUVOffsetRepeat( vUv, specularOffsetRepeat );", + "vec4 texelSpecular = applyGainBrightness( texelDecode( texture2D( specularMap, vSpecularUv ), ENCODING_sRGB ), specularGainBrightness );", - "#else", - - "specularStrength = 1.0;", + "#ifdef PHYSICAL", + "specularColor.rgb = clamp( specularColor.rgb * texelSpecular.rgb, vec3( 0.0 ), vec3( 1.0 ) );", + "#else", + "specularStrength = clamp( specularStrength * texelSpecular.r, 0.0, 1.0 );", + "#endif", - "#endif" + "#endif", ].join("\n"), @@ -20447,6 +21213,7 @@ THREE.ShaderChunk = { "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];", "#endif", @@ -20458,6 +21225,18 @@ THREE.ShaderChunk = { "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDecayExponent[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#if MAX_AREA_LIGHTS > 0", + + "uniform vec3 areaLightColor[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightPosition[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightWidth[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightHeight[ MAX_AREA_LIGHTS ];", + "uniform float areaLightDistance[ MAX_AREA_LIGHTS ];", + "uniform float areaLightDecayExponent[ MAX_AREA_LIGHTS ];", "#endif", @@ -20535,9 +21314,7 @@ THREE.ShaderChunk = { "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", "vec3 lVector = lPosition.xyz - mvPosition.xyz;", - "float lDistance = 1.0;", - "if ( pointLightDistance[ i ] > 0.0 )", - "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", + "float distanceAttenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );", "lVector = normalize( lVector );", "float dotProduct = dot( transformedNormal, lVector );", @@ -20569,11 +21346,11 @@ THREE.ShaderChunk = { "#endif", - "vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;", + "vLightFront += pointLightColor[ i ] * pointLightWeighting * distanceAttenuation;", "#ifdef DOUBLE_SIDED", - "vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;", + "vLightBack += pointLightColor[ i ] * pointLightWeightingBack * distanceAttenuation;", "#endif", @@ -20588,15 +21365,13 @@ THREE.ShaderChunk = { "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", "vec3 lVector = lPosition.xyz - mvPosition.xyz;", + "float distanceAttenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );", + "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );", "if ( spotEffect > spotLightAngleCos[ i ] ) {", - "spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", - - "float lDistance = 1.0;", - "if ( spotLightDistance[ i ] > 0.0 )", - "lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", + "spotEffect = pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] );", "lVector = normalize( lVector );", @@ -20628,11 +21403,11 @@ THREE.ShaderChunk = { "#endif", - "vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;", + "vLightFront += spotLightColor[ i ] * spotLightWeighting * distanceAttenuation * spotEffect;", "#ifdef DOUBLE_SIDED", - "vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;", + "vLightBack += spotLightColor[ i ] * spotLightWeightingBack * distanceAttenuation * spotEffect;", "#endif", @@ -20666,21 +21441,837 @@ THREE.ShaderChunk = { "#endif", - "vLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;", + "vLightFront = ( vLightFront + ambientLightColor + ambient) * diffuse + emissive;", "#ifdef DOUBLE_SIDED", - "vLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;", + "vLightBack = ( vLightFront + ambientLightColor + ambient) * diffuse + emissive;", "#endif" ].join("\n"), + // LIGHTS PHYSICAL + + lights_physical_pars_vertex: [ + + "#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", + + "varying vec3 vWorldPosition;", + + "#endif" + + ].join("\n"), + + + lights_physical_vertex: [ + + "#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", + + "vWorldPosition = worldPosition.xyz;", + + "#endif", + + "#ifdef USE_SKINNING", + + "vNormal = normalize( normalMatrix * skinnedNormal.xyz );", + + "vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );", + "vTangent = normalize( normalMatrix * skinnedTangent.xyz );", + + "#else", + + "vNormal = normalize( normalMatrix * normal );", + "vTangent = normalize( normalMatrix * tangent.xyz );", + + "#endif", + + "vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );", + + + ].join("\n"), + + lights_physical_pars_fragment: [ + + "uniform vec3 ambientLightColor;", + + "#if MAX_DIR_LIGHTS > 0", + + "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", + "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", + "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDecayExponent[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#if MAX_AREA_LIGHTS > 0", + + "uniform vec3 areaLightColor[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightPosition[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightWidth[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightHeight[ MAX_AREA_LIGHTS ];", + "uniform float areaLightDistance[ MAX_AREA_LIGHTS ];", + "uniform float areaLightDecayExponent[ MAX_AREA_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP )", + + "varying vec3 vWorldPosition;", + + "#endif", + + "#ifdef WRAP_AROUND", + + "uniform vec3 wrapRGB;", + + "#endif", + + "varying vec3 vViewPosition;", + "varying vec3 vTangent;", + "varying vec3 vBinormal;", + "varying vec3 vNormal;", + + // classic Fresnel Schlick + /*"float Fresnel_Schlick( float hDotV ) {", + "float F0 = 0.04;", + "return F0 + ( 1.0 - F0 ) * pow( 1.0 - hDotV, 5.0 );", + "}",*/ + + // Calcuate the Fresnel term using the Schlick approximation (using Unreal's blend to white method) VALIDATED + "vec3 Fresnel_Schlick_SpecularBlendToWhite(vec3 specularColor, float hDotV) {", + "float Fc = pow(max( 1.0 - hDotV, 0.0 ), 5.0);", + "return saturate( 50.0 * average( specularColor ) ) * Fc + (1.0 - Fc) * specularColor;", + "}", + + "vec3 Fresnel_Schlick_SpecularBlendToWhiteRoughness(vec3 specularColor, float hDotV, float roughness) {", + "float Fc = pow(max( 1.0 - hDotV, 0.0 ), 5.0) / ( 1.0 + 3.0 * roughness );", + + "return mix( specularColor, vec3( saturate( 50.0 * average( specularColor ) ) ), Fc );", + "}", + + // Calculate the distribution term VALIDATED + "float Distribution_GGX( float roughness2, float nDotH ) {", + "float denom = nDotH * nDotH * (roughness2 - 1.0) + 1.0;", + "return roughness2 / ( PI * square( denom ) + 0.0000001 );", + "}", + + // Calculated the anisotropic GGZ distrubtion term VALIDATED + "float Distribution_GGXAniso( vec2 anisotropicM, vec2 xyDotH, float nDotH ) {", + "float anisoTerm = ( xyDotH.x * xyDotH.x / ( anisotropicM.x * anisotropicM.x ) + xyDotH.y * xyDotH.y / ( anisotropicM.y * anisotropicM.y ) + nDotH * nDotH );", + "return 1.0 / ( PI * anisotropicM.x * anisotropicM.y * anisoTerm * anisoTerm + 0.0000001 );", + "}", + + // useful for clear coat surfaces, use with Distribution_GGX. + "float Visibility_Kelemen( float vDotH ) {", + "return 1.0 / ( 4.0 * vDotH * vDotH + 0.0000001 );", + "}", + + "float Visibility_Schlick( float roughness2, float nDotL, float nDotV) {", + "float termL = (nDotL + sqrt(roughness2 + (1.0 - roughness2) * nDotL * nDotL));", + "float termV = (nDotV + sqrt(roughness2 + (1.0 - roughness2) * nDotV * nDotV));", + "return 1.0 / ( abs( termL * termV ) + 0.0000001 );", + "}", + + "float Diffuse_Lambert() {", + "return 1.0 / PI;", + "}", + + "float Diffuse_OrenNayer( float m2, float nDotV, float nDotL, float vDotH ) {", + "float termA = 1.0 - 0.5 * m2 / (m2 + 0.33);", + "float Cosri = 2.0 * vDotH - 1.0 - nDotV * nDotL;", + "float termB = 0.45 * m2 / (m2 + 0.09) * Cosri * ( Cosri >= 0.0 ? min( 1.0, nDotL / nDotV ) : nDotL );", + "return 1.0 / PI * ( nDotL * termA + termB );", + "}", + + // Helper for anisotropy rotation + "mat2 createRotationMat2( float rads) {", + "float cos_rads = cos( rads );", + "float sin_rads = sin( rads );", + "return mat2( vec2( cos_rads, sin_rads ), vec2( -sin_rads, cos_rads ) );", + "}", + + // Helper for anisotropy rotation + "vec2 calcAnisotropyUV( float anisotropyLocal) {", + "float oneMinusAbsAnisotropy = 1.0 - min( abs( anisotropyLocal ) * 0.9, 0.9 );", + "vec2 anisotropyUV = vec2 ( 1.0 / oneMinusAbsAnisotropy, oneMinusAbsAnisotropy );", + "if( anisotropy < 0.0 ) {", + "anisotropyUV.xy = anisotropyUV.yx;", // swizzel + "}", + "return anisotropyUV;", + "}" + + //"float horizonOcclusion( vec3 reflectionVector, vec3 originalNormal ) {", + // "return quare( saturate( 1.0 + uHorizonOcclude*dot( dir, vertexNormal ) ) );", + //"}" + + + ].join("\n"), + + lights_physical_fragment: [ + + "mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normal );", + + "#ifdef USE_NORMALMAP", + + "normal = perturbNormal2Arb( -vViewPosition, normal );", + + /*"vec3 normalTex = texture2D( normalMap, vNormalUv ).xyz * 2.0 - 1.0;", + "normalTex.xy *= normalScale;", + "normalTex = perturbNormal2Arb( -viewDirection, normal );", + + "normal = tsb * normalTex;",*/ + + //"vec3 originalNormal = normal;", + "#endif", + + "#if defined( USE_BUMPMAP )", + + "normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );", + + "#endif", + + "#ifdef DOUBLE_SIDED", + + "normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + + "#endif", + + "#ifdef FALLOFF", + + "vec3 modulatedFalloffColor = falloffColor;", + + "#ifdef USE_FALLOFFMAP", + + "vec4 falloffTexelColor = texelDecode( texture2D( falloffMap, vUvLocal ), ENCODING_sRGB );", + + "modulatedFalloffColor = modulatedFalloffColor * falloffTexelColor.xyz;", + + "#endif", + + "float fm = abs( dot( normal, viewDirection ) );", + + // this is a hack, it needs to be fixed. + "fm = /*falloffBlendParams.x * fm + falloffBlendParams.y * */ ( fm * fm * ( 3.0 - 2.0 * fm ) );", + + "diffuseColor = mix( modulatedFalloffColor, diffuseColor, fm );", + + "#endif", + + "float nDotV = saturate( dot( normal, viewDirection ) );", + "float m2 = pow( clamp( roughnessStrength, 0.02, 1.0 ), 4.0 );", + // specular is scaled by 0.08 per Disney PBR recommendations. + "float m2ClearCoat = pow( clamp( clearCoatRoughness, 0.02, 1.0 ), 4.0 );", + + "specularColor = mix( specularColor * SPECULAR_COEFF, diffuseColor, metallicStrength );", + "diffuseColor *= ( 1.0 - metallicStrength );", + + "#ifdef ANISOTROPY", + + "vec2 anisotropicM = calcAnisotropyUV( anisotropyStrength ) * sqrt( m2 );", + + "#ifdef ANISOTROPYROTATION", + "mat2 anisotropicRotationMatrix = createRotationMat2( anisotropyRotationStrength * 2.0 * PI );", + "#endif", + + "vec3 anisotropicS = tsb[1];", // binormal in eye space. + "vec3 anisotropicT = tsb[0];", // tangent in eye space. + + "#endif", + + "vec3 totalLighting = vec3( 0.0 );", + + "#if ( defined( USE_ENVMAP ) || defined( USE_DIFFUSEENVMAP ) ) && defined( PHYSICAL )", + + "{", + + "vec3 worldNormal = vec3( normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz ) );", + "vec3 worldView = -vec3( normalize( ( vec4( viewDirection, 0.0 ) * viewMatrix ).xyz ) );", + + "vec3 reflectVec = reflect( worldView, worldNormal );", + + "vec3 hVector = normal;//normalize( viewDirection.xyz + lVector.xyz );", + "float nDotH = saturate( dot( normal, normal ) );", + "float hDotV = saturate( dot( normal, viewDirection ) );", + "float nDotL = hDotV;//saturate( dot( normal, lVector ) );", + + + "vec3 queryVector = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );", + + "#ifdef DOUBLE_SIDED", + + "queryVector *= ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + + "#endif", + + "vec3 worldEnvNormal = vec3( normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz ) );", + "worldEnvNormal = vec3( flipEnvMap * worldEnvNormal.x, worldEnvNormal.yz );", + + "#ifdef DOUBLE_SIDED", + + "worldEnvNormal *= ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + + "#endif", + + // calculate diffuse map contribution + + "vec4 diffuseEnvColor = vec4( 0.0, 0.0, 0.0, 1.0 );", + + "#if defined( USE_DIFFUSEENVMAP )", + + "diffuseEnvColor = texelDecode( textureCube( diffuseEnvMap, worldEnvNormal ), diffuseEnvEncoding );", + + "#elif defined( USE_ENVMAP )", + + "#if defined( TEXTURE_CUBE_LOD_EXT )", + + "diffuseEnvColor = texelDecode( textureCubeLodEXT( envMap, worldEnvNormal, 9.5 ), envEncoding );", + + "#else", + + "diffuseEnvColor = texelDecode( textureCube( envMap, worldEnvNormal, 10.0 ), envEncoding );", + + "#endif", + + "#endif", + + // calculate specular map contribution + + "vec4 specularEnvColor = vec4( 0.0, 0.0, 0.0, 1.0 );", + + "#if defined( USE_ENVMAP )", + + "#if defined( TEXTURE_CUBE_LOD_EXT )", + + "float specularMIPLevel = 9.7925 - 0.5 * log2( 2.0 / ( roughness * roughness + 0.00001 ) - 1.0 );", + "specularEnvColor = texelDecode( textureCubeLodEXT( envMap, queryVector, specularMIPLevel ), envEncoding );", + + "#else", + + "specularEnvColor = mix( texelDecode( textureCube( envMap, queryVector ), envEncoding ), texelDecode( textureCube( envMap, queryVector, 10.0 ), envEncoding ), roughnessStrength );", + + "#endif", + + "#endif", + + "vec3 specClearCoat = vec3(0, 0, 0);", + + "#if defined( CLEARCOAT ) && defined( USE_ENVMAP )", + + "#if defined( TEXTURE_CUBE_LOD_EXT )", + + "float clearCoatMIPLevel = 9.7925 - 0.5 * log2( 2.0 / ( clearCoatRoughness * clearCoatRoughness + 0.00001 ) - 1.0 );", + "vec4 specularClearCoatEnvColor = texelDecode( textureCubeLodEXT( envMap, queryVector, clearCoatMIPLevel ), envEncoding );", + + "#else", + + "vec4 specularClearCoatEnvColor = mix( texelDecode( textureCube( envMap, queryVector ), envEncoding ), texelDecode( textureCube( envMap, queryVector, 10.0 ), envEncoding ), clearCoatRoughness );", + + "#endif", + + "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhiteRoughness( vec3( SPECULAR_COEFF ), nDotL, m2ClearCoat );", + "specClearCoat = specularClearCoatEnvColor.rgb * fresnelClearCoat;", + + "#endif", + + "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhiteRoughness( specularColor, nDotL, m2 );", + + // Put it all together + "vec3 spec = fresnelColor * specularEnvColor.rgb;", + "vec3 diff = diffuseColor * diffuseEnvColor.rgb;", // no Diffuse_Lambert() term, it is baked into irradiance. + + "vec3 shadingResult = spec + diff;", + + "#ifdef CLEARCOAT", + + "shadingResult = mix( shadingResult, specClearCoat, clearCoat );", + + "#endif", + // diffuse + "totalLighting += shadingResult;", + + "}", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + "float distanceAttenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );", + + "vec3 incidentLight = pointLightColor[ i ] * distanceAttenuation;", + + "lVector = normalize( lVector );", + + // diffuse + + "vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );", + "float nDotH = saturate( dot( normal, hVector ) );", + "float nDotL = saturate( dot( normal, lVector ) );", + "float hDotV = saturate( dot( hVector, viewDirection ) );", + + "#ifdef CLEARCOAT", + + "float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );", + "float visClearCoat = Visibility_Kelemen( hDotV );", + "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );", + "vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;", + + "#endif", + + "#ifdef ANISOTROPY", + + "vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );", + + "#ifdef ANISOTROPYROTATION", + "xyDotH = anisotropicRotationMatrix * xyDotH;", + "#endif", + + "float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );", + + "#else", + + "float d = Distribution_GGX( m2, nDotH );", + + "#endif", + + "float vis = Visibility_Schlick(m2, nDotL, nDotV);", + "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );", + + // Put it all together + "vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;", + "vec3 diff = nDotL * Diffuse_Lambert() * diffuseColor;", + + "#ifdef TRANSLUCENCY", + + "diff *= whiteCompliment( translucencyColor.xyz );", + + "#endif", + + "vec3 shadingResult = spec + diff;", + + "#ifdef CLEARCOAT", + + "shadingResult = mix( shadingResult, specClearCoat, clearCoat );", + + "#endif", + // diffuse + "totalLighting += incidentLight * shadingResult;", + + "#ifdef TRANSLUCENCY", + + "float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );", + + "float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );", + + "totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;", + + "#endif", + + "}", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + "float distanceAttenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );", + + "vec3 incidentLight = spotLightColor[ i ] * distanceAttenuation;", + + "lVector = normalize( lVector );", + + "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", + + "if ( spotEffect > spotLightAngleCos[ i ] ) {", + + "spotEffect = pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] );", + + // diffuse + + "incidentLight *= spotEffect;", + + "vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );", + "float nDotH = saturate( dot( normal, hVector ) );", + "float nDotL = saturate( dot( normal, lVector ) );", + "float hDotV = saturate( dot( hVector, viewDirection ) );", + + "#ifdef CLEARCOAT", + + "float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );", + "float visClearCoat = Visibility_Kelemen( hDotV );", + "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );", + "vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;", + + "#endif", + + "#ifdef ANISOTROPY", + + "vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );", + + "#ifdef ANISOTROPYROTATION", + "xyDotH = anisotropicRotationMatrix * xyDotH;", + "#endif", + + "float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );", + + "#else", + + "float d = Distribution_GGX( m2, nDotH );", + + "#endif", + + "float vis = Visibility_Schlick(m2, nDotL, nDotV);", + "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );", + + // Put it all together + "vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;", + "vec3 diff = nDotL * Diffuse_Lambert() * diffuseColor;", + + "#ifdef TRANSLUCENCY", + + "diff *= whiteCompliment( translucencyColor.xyz );", + + "#endif", + + "vec3 shadingResult = spec + diff;", + + "#ifdef CLEARCOAT", + + "shadingResult = mix( shadingResult, specClearCoat, clearCoat );", + + "#endif", + // diffuse + "totalLighting += incidentLight * shadingResult;", + + "#ifdef TRANSLUCENCY", + + "float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );", + + "float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );", + + "totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;", + + "#endif", + + "}", + + "}", + + "#endif", + + "#if MAX_DIR_LIGHTS > 0", + + "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", + "vec3 lVector = normalize( lDirection.xyz );", + + "vec3 incidentLight = directionalLightColor[ i ];", + + "vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );", + "float nDotH = saturate( dot( normal, hVector ) );", + "float nDotL = saturate( dot( normal, lVector ) );", + "float hDotV = saturate( dot( hVector, viewDirection ) );", + + "#ifdef CLEARCOAT", + + "float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );", + "float visClearCoat = Visibility_Kelemen( hDotV );", + "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );", + "vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;", + + "#endif", + + "#ifdef ANISOTROPY", + + "vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );", + + "#ifdef ANISOTROPYROTATION", + "xyDotH = anisotropicRotationMatrix * xyDotH;", + "#endif", + + "float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );", + + "#else", + + "float d = Distribution_GGX( m2, nDotH );", + + "#endif", + + "float vis = Visibility_Schlick(m2, nDotL, nDotV);", + "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );", + + // Put it all together + "vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;", + "vec3 diff = nDotL * Diffuse_Lambert() * diffuseColor;", + + "#ifdef TRANSLUCENCY", + + "diff *= whiteCompliment( translucencyColor.xyz );", + + "#endif", + + "vec3 shadingResult = spec + diff;", + + "#ifdef CLEARCOAT", + + "shadingResult = mix( shadingResult, specClearCoat, clearCoat );", + + "#endif", + // diffuse + "totalLighting += incidentLight * shadingResult;", + + "#ifdef TRANSLUCENCY", + + "float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );", + + "float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );", + + "totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;", + + "#endif", + + "}", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", + "vec3 lVector = normalize( lDirection.xyz );", + + // diffuse + + "float nDotL = dot( normal, lVector );", + + // based on page 325 of Real-Time Rendering., equation (8.43) + "vec3 hemiColor = ( PI / 2.0 ) * ( ( 1.0 + nDotL ) * hemisphereLightSkyColor[ i ] + ( 1.0 - nDotL ) * hemisphereLightGroundColor[ i ] );", + + "totalLighting += diffuseColor * hemiColor;", + + "}", + + "#endif", + + "#if MAX_AREA_LIGHTS > 0", + + "for( int i = 0; i < MAX_AREA_LIGHTS; i ++ ) {", + + "vec3 lPosition = ( viewMatrix * vec4( areaLightPosition[ i ], 1.0 ) ).xyz;", + //"vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + "vec3 width = areaLightWidth[ i ];", + "vec3 height = areaLightHeight[ i ];", + "vec3 up = normalize( ( viewMatrix * vec4( height, 0.0 ) ).xyz );", + "vec3 right = normalize( ( viewMatrix * vec4( width, 0.0 ) ).xyz );", + "vec3 pnormal = normalize( cross( right, up ) );", + + "float widthScalar = length( width );", + "float heightScalar = length( height );", + + //project onto plane and calculate direction from center to the projection. + "vec3 projection = projectOnPlane( -vViewPosition.xyz, lPosition, pnormal );", // projection in plane + "vec3 dir = projection - lPosition;", + + //calculate distance from area: + "vec2 diagonal = vec2( dot( dir, right ), dot( dir, up ) );", + "vec2 nearest2D = vec2( clamp( diagonal.x, -widthScalar, widthScalar ), clamp( diagonal.y, -heightScalar, heightScalar ) );", + "vec3 nearestPointInside = lPosition + ( right *nearest2D.x + up * nearest2D.y );", + + "vec3 lVector = ( nearestPointInside + vViewPosition.xyz );", + "float distanceAttenuation = calcLightAttenuation( length( lVector ), areaLightDistance[ i ], areaLightDecayExponent[i] );", + "lVector = normalize( lVector );", + + "vec3 incidentLight = areaLightColor[ i ] * distanceAttenuation * 0.01;", // the 0.01 is the area light intensity scaling. + + "float nDotLDiffuse = saturate( dot( normal, lVector ) );", + + "vec3 diff = Diffuse_Lambert() * diffuseColor * widthScalar * heightScalar;", + + "vec3 viewReflection = reflect( viewDirection.xyz, normal );", + "vec3 reflectionLightPlaneIntersection = linePlaneIntersect( -vViewPosition.xyz, viewReflection, lPosition, pnormal );", + + "float specAngle = dot( viewReflection, pnormal );", + + // && dot( -vViewPosition.xyz - areaLightPosition[ i ], -pnormal ) >= 0.0 + "if ( specAngle < 0.0 ) {", + + "vec3 dirSpec = reflectionLightPlaneIntersection - lPosition;", + "vec2 dirSpec2D = vec2( dot( dirSpec, right ), dot( dirSpec, up ) );", + "vec2 nearestSpec2D = vec2( clamp( dirSpec2D.x, -widthScalar, widthScalar ), clamp( dirSpec2D.y, -heightScalar, heightScalar ) );", + "lVector = normalize( lPosition + ( right *nearestSpec2D.x + up * nearestSpec2D.y ) + vViewPosition.xyz );", + + "} else { ", + + "lVector = vec3( 0 );", + + "}", + + "vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );", + "float nDotH = saturate( dot( normal, hVector ) );", + "float nDotL = saturate( dot( normal, lVector ) );", + "float hDotV = saturate( dot( hVector, viewDirection ) );", + + "#ifdef CLEARCOAT", + + "float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );", + "float visClearCoat = Visibility_Kelemen( hDotV );", + "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );", + "vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;", + + "#endif", + + "#ifdef TRANSLUCENCY", + + "diff *= whiteCompliment( translucencyColor.xyz );", + + "#endif", + + "#ifdef CLEARCOAT", + + "diff = mix( diff, specClearCoat, clearCoat );", + + "#endif", + + + "#ifdef ANISOTROPY", + + "vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );", + + "#ifdef ANISOTROPYROTATION", + "xyDotH = anisotropicRotationMatrix * xyDotH;", + "#endif", + + "float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );", + + "#else", + + "float d = Distribution_GGX( m2, nDotH );", + + "#endif", + + "float vis = Visibility_Schlick(m2, nDotL, nDotV);", + "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );", + + // Put it all together + "vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;", + + "totalLighting += incidentLight * spec;", + "totalLighting += incidentLight * nDotLDiffuse * diff;", + + "#ifdef TRANSLUCENCY", + + "float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );", + + "float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );", + + "totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;", + + "#endif", + + "}", + + "#endif", + + "#ifdef CLEARCOAT", + + "totalLighting += diffuseColor * ( ambientLightColor * ( 1.0 - clearCoat ) );", + + "#else", + + "totalLighting += diffuseColor * ambientLightColor;", + + "#endif", + + "gl_FragColor.xyz += totalLighting;", + + "vec3 emissiveLocal = emissive;", + + "#ifdef USE_EMISSIVEMAP", + + "vec3 emissiveColor = texture2D( emissiveMap, vUv2 ).xyz;", + + "#ifdef GAMMA_INPUT", + + "emissiveColor *= emissiveColor;", + + "#endif", + + "emissiveLocal *= emissiveColor;", + + "#endif", + + "gl_FragColor.xyz += emissiveLocal;", + + "vec3 ambientLocal = ambient;", + + "#ifdef USE_LIGHTMAP", + + "vec3 ambientColor = texture2D( lightMap, vUv2 ).xyz;", + + "#ifdef GAMMA_INPUT", + + "ambientColor *= ambientColor;", + + "#endif", + + "ambientLocal *= ambientColor;", + + "#ifdef CLEARCOAT", + + "ambientLocal *= ( 1.0 - clearCoat );", + + "#endif", + + "#endif", + + "gl_FragColor.xyz += diffuseColor * ambientLocal;", + + ].join("\n"), + // LIGHTS PHONG lights_phong_pars_vertex: [ - "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )", + "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", "varying vec3 vWorldPosition;", @@ -20691,7 +22282,7 @@ THREE.ShaderChunk = { lights_phong_vertex: [ - "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )", + "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", "vWorldPosition = worldPosition.xyz;", @@ -20721,9 +22312,9 @@ THREE.ShaderChunk = { "#if MAX_POINT_LIGHTS > 0", "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", - "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];", "#endif", @@ -20734,12 +22325,23 @@ THREE.ShaderChunk = { "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDecayExponent[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#if MAX_AREA_LIGHTS > 0", + + "uniform vec3 areaLightColor[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightPosition[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightWidth[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightHeight[ MAX_AREA_LIGHTS ];", + "uniform float areaLightDistance[ MAX_AREA_LIGHTS ];", + "uniform float areaLightDecayExponent[ MAX_AREA_LIGHTS ];", "#endif", - "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )", + "#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP )", "varying vec3 vWorldPosition;", @@ -20759,7 +22361,7 @@ THREE.ShaderChunk = { lights_phong_fragment: [ "vec3 normal = normalize( vNormal );", - "vec3 viewPosition = normalize( vViewPosition );", + "vec3 viewDirection = normalize( vViewPosition );", "#ifdef DOUBLE_SIDED", @@ -20787,9 +22389,7 @@ THREE.ShaderChunk = { "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", - "float lDistance = 1.0;", - "if ( pointLightDistance[ i ] > 0.0 )", - "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", + "float distanceAttenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );", "lVector = normalize( lVector );", @@ -20797,33 +22397,22 @@ THREE.ShaderChunk = { "float dotProduct = dot( normal, lVector );", - "#ifdef WRAP_AROUND", - - "float pointDiffuseWeightFull = max( dotProduct, 0.0 );", - "float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", - - "vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );", + "float pointDiffuseWeight = max( dotProduct, 0.0 );", - "#else", - - "float pointDiffuseWeight = max( dotProduct, 0.0 );", - - "#endif", - - "pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;", + "pointDiffuse += pointLightColor[ i ] * pointDiffuseWeight * distanceAttenuation;", // specular - "vec3 pointHalfVector = normalize( lVector + viewPosition );", + "vec3 pointHalfVector = normalize( lVector + viewDirection );", "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", - "float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );", + "float pointSpecularWeight = specularStrength * pow( max( pointDotNormalHalf, 0.0 ), shininess );", // 2.0 => 2.0001 is hack to work around ANGLE bug "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );", - "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;", + "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * distanceAttenuation * specularNormalization;", "}", @@ -20839,9 +22428,7 @@ THREE.ShaderChunk = { "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", - "float lDistance = 1.0;", - "if ( spotLightDistance[ i ] > 0.0 )", - "lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", + "float distanceAttenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );", "lVector = normalize( lVector );", @@ -20849,7 +22436,7 @@ THREE.ShaderChunk = { "if ( spotEffect > spotLightAngleCos[ i ] ) {", - "spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + "spotEffect = pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] );", // diffuse @@ -20868,20 +22455,20 @@ THREE.ShaderChunk = { "#endif", - "spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;", + "spotDiffuse += spotLightColor[ i ] * spotDiffuseWeight * distanceAttenuation * spotEffect;", // specular - "vec3 spotHalfVector = normalize( lVector + viewPosition );", + "vec3 spotHalfVector = normalize( lVector + viewDirection );", "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", - "float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );", + "float spotSpecularWeight = specularStrength * pow( max( spotDotNormalHalf, 0.0 ), shininess );", // 2.0 => 2.0001 is hack to work around ANGLE bug "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );", - "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;", + "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * distanceAttenuation * specularNormalization * spotEffect;", "}", @@ -20916,32 +22503,13 @@ THREE.ShaderChunk = { "#endif", - "dirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;", + "dirDiffuse += directionalLightColor[ i ] * dirDiffuseWeight;", // specular - "vec3 dirHalfVector = normalize( dirVector + viewPosition );", + "vec3 dirHalfVector = normalize( dirVector + viewDirection );", "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", - "float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );", - - /* - // fresnel term from skin shader - "const float F0 = 0.128;", - - "float base = 1.0 - dot( viewPosition, dirHalfVector );", - "float exponential = pow( base, 5.0 );", - - "float fresnel = exponential + F0 * ( 1.0 - exponential );", - */ - - /* - // fresnel term from fresnel shader - "const float mFresnelBias = 0.08;", - "const float mFresnelScale = 0.3;", - "const float mFresnelPower = 5.0;", - - "float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );", - */ + "float dirSpecularWeight = specularStrength * pow( max( dirDotNormalHalf, 0.0 ), shininess );", // 2.0 => 2.0001 is hack to work around ANGLE bug @@ -20974,21 +22542,21 @@ THREE.ShaderChunk = { "vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", - "hemiDiffuse += diffuse * hemiColor;", + "hemiDiffuse += hemiColor;", // specular (sky light) - "vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", + "vec3 hemiHalfVectorSky = normalize( lVector + viewDirection );", "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", - "float hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", + "float hemiSpecularWeightSky = specularStrength * pow( max( hemiDotNormalHalfSky, 0.0 ), shininess );", // specular (ground light) "vec3 lVectorGround = -lVector;", - "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", + "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewDirection );", "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", - "float hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", + "float hemiSpecularWeightGround = specularStrength * pow( max( hemiDotNormalHalfGround, 0.0 ), shininess );", "float dotProductGround = dot( normal, lVectorGround );", @@ -21004,6 +22572,83 @@ THREE.ShaderChunk = { "#endif", + "#if MAX_AREA_LIGHTS > 0", + + "vec3 areaDiffuse = vec3( 0.0 );", + "vec3 areaSpecular = vec3( 0.0 );", + + "for( int i = 0; i < MAX_AREA_LIGHTS; i ++ ) {", + + "vec3 lPosition = ( viewMatrix * vec4( areaLightPosition[ i ], 1.0 ) ).xyz;", + //"vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + "vec3 width = areaLightWidth[ i ];", + "vec3 height = areaLightHeight[ i ];", + "vec3 up = normalize( ( viewMatrix * vec4( height, 0.0 ) ).xyz );", + "vec3 right = normalize( ( viewMatrix * vec4( width, 0.0 ) ).xyz );", + "vec3 pnormal = normalize( cross( right, up ) );", + + "float widthScalar = length( width );", + "float heightScalar = length( height );", + + //project onto plane and calculate direction from center to the projection. + "vec3 projection = projectOnPlane( -vViewPosition.xyz, lPosition, pnormal );", // projection in plane + "vec3 dir = projection - lPosition;", + + //calculate distance from area: + "vec2 diagonal = vec2( dot( dir, right ), dot( dir, up ) );", + "vec2 nearest2D = vec2( clamp( diagonal.x, -widthScalar, widthScalar ), clamp( diagonal.y, -heightScalar, heightScalar ) );", + "vec3 nearestPointInside = lPosition + ( right *nearest2D.x + up * nearest2D.y );", + + "vec3 lVector = ( nearestPointInside + vViewPosition.xyz );", + "float distanceAttenuation = calcLightAttenuation( length( lVector ), areaLightDistance[ i ], areaLightDecayExponent[i] );", + "lVector = normalize( lVector );", + + "float nDotLDiffuse = saturate( dot( normal, lVector ) );", + + "vec3 viewReflection = reflect( viewDirection.xyz, normal );", + "vec3 reflectionLightPlaneIntersection = linePlaneIntersect( -vViewPosition.xyz, viewReflection, lPosition, pnormal );", + + "float specAngle = dot( viewReflection, pnormal );", + + "if ( specAngle < 0.0 ) {", + + "vec3 dirSpec = reflectionLightPlaneIntersection - lPosition;", + "vec2 dirSpec2D = vec2( dot( dirSpec, right ), dot( dirSpec, up ) );", + "vec2 nearestSpec2D = vec2( clamp( dirSpec2D.x, -widthScalar, widthScalar ), clamp( dirSpec2D.y, -heightScalar, heightScalar ) );", + "lVector = normalize( lPosition + ( right *nearestSpec2D.x + up * nearestSpec2D.y ) + vViewPosition.xyz );", + + "} else { ", + + "lVector = vec3( 0 );", + + "}", + + // diffuse + + "float dotProduct = nDotLDiffuse;", + + "float areaDiffuseWeight = max( dotProduct, 0.0 );", + + "areaDiffuse += areaLightColor[ i ] * areaDiffuseWeight * distanceAttenuation * widthScalar * heightScalar * 0.01;", // the 0.01 is the area light intensity scaling. + + // specular + + "vec3 areaHalfVector = normalize( lVector + viewDirection );", + "float areaDotNormalHalf = max( dot( normal, areaHalfVector ), 0.0 );", + "float areaSpecularWeight = specularStrength * pow( max( areaDotNormalHalf, 0.0 ), shininess );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, areaHalfVector ), 0.0 ), 5.0 );", + "areaSpecular += schlick * areaLightColor[ i ] * areaSpecularWeight * areaDiffuseWeight * distanceAttenuation * specularNormalization * 0.01;", // the 0.01 is the area light intensity scaling. + + "}", + + "#endif", + "vec3 totalDiffuse = vec3( 0.0 );", "vec3 totalSpecular = vec3( 0.0 );", @@ -21035,15 +22680,47 @@ THREE.ShaderChunk = { "#endif", - "#ifdef METAL", + "#if MAX_AREA_LIGHTS > 0", - "gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );", + "totalDiffuse += areaDiffuse;", + "totalSpecular += areaSpecular;", - "#else", + "#endif", + "vec3 ambientLocal = ambient;", - "gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;", + "#ifdef USE_LIGHTMAP", - "#endif" + "vec3 ambientColor = texture2D( lightMap, vUv2 ).xyz;", + + "#ifdef GAMMA_INPUT", + + "ambientColor *= ambientColor;", + + "#endif", + + "ambientLocal *= ambientColor;", + + "#endif", + + "gl_FragColor.xyz = diffuseColor * ( totalDiffuse + ambientLightColor + ambientLocal ) + totalSpecular;", + + "vec3 emissiveLocal = emissive;", + + "#ifdef USE_EMISSIVEMAP", + + "vec3 emissiveColor = texture2D( emissiveMap, vUv2 ).xyz;", + + "#ifdef GAMMA_INPUT", + + "emissiveColor *= emissiveColor;", + + "#endif", + + "emissiveLocal *= emissiveColor;", + + "#endif", + + "gl_FragColor.xyz += emissiveLocal.xyz;", ].join("\n"), @@ -21111,7 +22788,7 @@ THREE.ShaderChunk = { "uniform int boneTextureWidth;", "uniform int boneTextureHeight;", - "mat4 getBoneMatrix( const in float i ) {", + "mat4 getBoneMatrix( const float i ) {", "float j = i * 4.0;", "float x = mod( j, float( boneTextureWidth ) );", @@ -21137,7 +22814,7 @@ THREE.ShaderChunk = { "uniform mat4 boneGlobalMatrices[ MAX_BONES ];", - "mat4 getBoneMatrix( const in float i ) {", + "mat4 getBoneMatrix( const float i ) {", "mat4 bone = boneGlobalMatrices[ int(i) ];", "return bone;", @@ -21345,7 +23022,7 @@ THREE.ShaderChunk = { "varying vec4 vShadowCoord[ MAX_SHADOWS ];", - "float unpackDepth( const in vec4 rgba_depth ) {", + "float unpackDepth( const vec4 rgba_depth ) {", "const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );", "float depth = dot( rgba_depth, bit_shift );", @@ -21512,7 +23189,7 @@ THREE.ShaderChunk = { "vec3 shadowZ = vec3( shadowCoord.z );", "shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));", "shadowKernel[0] *= vec3(0.25);", - + "shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));", "shadowKernel[1] *= vec3(0.25);", @@ -21632,7 +23309,8 @@ THREE.ShaderChunk = { ].join("\n") -};/** +}; +/** * Uniform Utilities */ @@ -21697,7 +23375,8 @@ THREE.UniformsUtils = { } -};/** +}; +/** * Uniforms library for shared webgl shaders */ @@ -21710,11 +23389,14 @@ THREE.UniformsLib = { "map" : { type: "t", value: null }, "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "gainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, "lightMap" : { type: "t", value: null }, - "specularMap" : { type: "t", value: null }, - + "emissiveMap" : { type: "t", value: null }, "envMap" : { type: "t", value: null }, + "envEncoding" : { type: "i", value: 0 }, + "diffuseEnvMap" : { type: "t", value: null }, + "diffuseEnvEncoding" : { type: "i", value: 0 }, "flipEnvMap" : { type: "f", value: -1 }, "useRefract" : { type: "i", value: 0 }, "reflectivity" : { type: "f", value: 1.0 }, @@ -21725,17 +23407,36 @@ THREE.UniformsLib = { }, - bump: { + specularmap: { + + "specularMap" : { type: "t", value: null }, + "specularOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "specularGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, + + }, + + bumpmap: { "bumpMap" : { type: "t", value: null }, - "bumpScale" : { type: "f", value: 1 } + "bumpScale" : { type: "f", value: 1 }, // used instead of 'bumpGainBrightness' + "bumpOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) } + + }, + + opacitymap: { + + "opacityMap" : { type: "t", value: null }, + "opacityOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "opacityGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, }, normalmap: { "normalMap" : { type: "t", value: null }, - "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) } + "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }, // used instead of 'normalGainBrightness' + "normalOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) } + }, fog : { @@ -21761,13 +23462,22 @@ THREE.UniformsLib = { "pointLightColor" : { type: "fv", value: [] }, "pointLightPosition" : { type: "fv", value: [] }, "pointLightDistance" : { type: "fv1", value: [] }, + "pointLightDecayExponent" : { type: "fv1", value: [] }, "spotLightColor" : { type: "fv", value: [] }, "spotLightPosition" : { type: "fv", value: [] }, "spotLightDirection" : { type: "fv", value: [] }, "spotLightDistance" : { type: "fv1", value: [] }, + "spotLightDecayExponent" : { type: "fv1", value: [] }, "spotLightAngleCos" : { type: "fv1", value: [] }, - "spotLightExponent" : { type: "fv1", value: [] } + "spotLightExponent" : { type: "fv1", value: [] }, + + "areaLightColor" : { type: "fv", value: [] }, + "areaLightPosition" : { type: "fv", value: [] }, + "areaLightDistance" : { type: "fv1", value: [] }, + "areaLightDecayExponent" : { type: "fv1", value: [] }, + "areaLightWidth" : { type: "fv", value: [] }, + "areaLightHeight" : { type: "fv", value: [] } }, @@ -21798,17 +23508,231 @@ THREE.UniformsLib = { } -};/** +}; +/** * Webgl Shader Library for three.js * * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ * @author mikael emtinger / http://gomo.se/ + * @author bhouston / http://clara.io/ */ THREE.ShaderLib = { + + 'physical': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "bumpmap" ], + THREE.UniformsLib[ "normalmap" ], + //THREE.UniformsLib[ "roughnessmap" ], TODO: Implement me! + //THREE.UniformsLib[ "metallicmap" ], TODO: Implement me! + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], + THREE.UniformsLib[ "opacitymap" ], + THREE.UniformsLib[ "specularmap" ], + + { + "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "specular" : { type: "c", value: new THREE.Color( 0xFFFFFF ) }, + "falloffColor" : { type: "c", value: new THREE.Color( 0xFFFFFF ) }, + "falloffMap" : { type: "t", value: null }, + "falloffBlendParams" : { type: "v4", value: new THREE.Vector4( 1, 0, 0, 1 ) }, + + "clearCoat": { type: "f", value: 0.0 }, + "clearCoatRoughness": { type: "f", value: 0.25 }, + + "roughness": { type: "f", value: 0.5 }, + "roughnessMap" : { type: "t", value: null }, + "roughnessOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "roughnessGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, + + "metallic": { type: "f", value: 0.5 }, + "metallicMap" : { type: "t", value: null }, + "metallicOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "metallicGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, + + "anisotropy": { type: "f", value: 0.0 }, + "anisotropyMap" : { type: "t", value: null }, + "anisotropyOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "anisotropyGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, + + "anisotropyRotation": { type: "f", value: 0.0 }, + "anisotropyRotationMap" : { type: "t", value: null }, + "anisotropyRotationOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "anisotropyRotationGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, + + "translucency" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "translucencyMap" : { type: "t", value: null }, + "translucencyNormalAlpha": { type: "f", value: 0.75 }, + "translucencyNormalPower": { type: "f", value: 2.0 }, + "translucencyViewAlpha": { type: "f", value: 0.75 }, + "translucencyViewPower": { type: "f", value: 2.0 }, + + } + + ] ), + + vertexShader: [ + + "attribute vec4 tangent;", + + "#define PHONG", + "#define PHYSICAL", + + "varying vec3 vViewPosition;", + "varying vec3 vTangent;", + "varying vec3 vBinormal;", + "varying vec3 vNormal;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "normalmap_pars_vertex" ], + THREE.ShaderChunk[ "roughnessmap_pars_vertex" ], + THREE.ShaderChunk[ "specularmap_pars_vertex" ], + THREE.ShaderChunk[ "opacitymap_pars_vertex" ], + THREE.ShaderChunk[ "anisotropymap_pars_vertex" ], + THREE.ShaderChunk[ "anisotropyrotationmap_pars_vertex" ], + THREE.ShaderChunk[ "metallicmap_pars_vertex" ], + THREE.ShaderChunk[ "translucencymap_pars_vertex" ], + THREE.ShaderChunk[ "bumpmap_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "lights_physical_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "normalmap_vertex" ], + THREE.ShaderChunk[ "roughnessmap_vertex" ], + THREE.ShaderChunk[ "opacitymap_vertex" ], + THREE.ShaderChunk[ "specularmap_vertex" ], + THREE.ShaderChunk[ "anisotropymap_vertex" ], + THREE.ShaderChunk[ "anisotropyrotationmap_vertex" ], + THREE.ShaderChunk[ "metallicmap_vertex" ], + THREE.ShaderChunk[ "translucencymap_vertex" ], + THREE.ShaderChunk[ "bumpmap_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], + + "vNormal = normalize( transformedNormal );", + + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + + "vViewPosition = -mvPosition.xyz;", + + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "lights_physical_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "#ifdef TEXTURE_CUBE_LOD_EXT", + "#extension GL_EXT_shader_texture_lod : enable", + "#endif", + "#define PHYSICAL", + "uniform vec3 diffuse;", + "uniform float opacity;", + + "uniform vec3 ambient;", + "uniform vec3 emissive;", + "uniform vec3 falloffColor;", + "uniform vec4 falloffBlendParams;", + "uniform vec3 specular;", + "uniform float roughness;", + "uniform float metallic;", + "uniform float clearCoat;", + "uniform float clearCoatRoughness;", + + "uniform vec3 translucency;", + "uniform float translucencyNormalAlpha;", + "uniform float translucencyNormalPower;", + "uniform float translucencyViewPower;", + "uniform float translucencyViewAlpha;", + + "uniform float anisotropy;", + "uniform float anisotropyRotation;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "falloffmap_pars_fragment" ], + THREE.ShaderChunk[ "opacitymap_pars_fragment" ], + THREE.ShaderChunk[ "translucencymap_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "diffuseenvmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "lights_physical_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "bumpmap_pars_fragment" ], + THREE.ShaderChunk[ "normalmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + THREE.ShaderChunk[ "anisotropymap_pars_fragment" ], + THREE.ShaderChunk[ "anisotropyrotationmap_pars_fragment" ], + THREE.ShaderChunk[ "metallicmap_pars_fragment" ], + THREE.ShaderChunk[ "roughnessmap_pars_fragment" ], + THREE.ShaderChunk[ "reflectivitymap_pars_fragment" ], + THREE.ShaderChunk[ "lightattenuation_func_fragment" ], + + "void main() {", + + "gl_FragColor = vec4( vec3 ( 0.0 ), opacity );", + "vec3 diffuseColor = diffuse;", + "vec3 translucencyColor = translucency;", + "vec3 normal = normalize( vNormal );", + "vec3 viewDirection = normalize( vViewPosition );", + + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "opacitymap_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], + THREE.ShaderChunk[ "anisotropymap_fragment" ], + THREE.ShaderChunk[ "anisotropyrotationmap_fragment" ], + THREE.ShaderChunk[ "roughnessmap_fragment" ], + THREE.ShaderChunk[ "metallicmap_fragment" ], + THREE.ShaderChunk[ "translucencymap_fragment" ], + THREE.ShaderChunk[ "reflectivitymap_fragment" ], + + THREE.ShaderChunk[ "lights_physical_fragment" ], + + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + + THREE.ShaderChunk[ "fog_fragment" ], + + "gl_FragColor.xyz *= gl_FragColor.w;", // premultipled, must be used with CustomBlender, OneFactor, OneMinusSrcAlphaFactor, AddEquation. + + "}" + + ].join("\n") + + }, + 'basic': { uniforms: THREE.UniformsUtils.merge( [ @@ -21821,9 +23745,9 @@ THREE.ShaderLib = { vertexShader: [ + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "map_pars_vertex" ], THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "envmap_pars_vertex" ], THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], @@ -21849,7 +23773,6 @@ THREE.ShaderLib = { THREE.ShaderChunk[ "default_vertex" ], THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "envmap_vertex" ], THREE.ShaderChunk[ "shadowmap_vertex" ], "}" @@ -21861,6 +23784,7 @@ THREE.ShaderLib = { "uniform vec3 diffuse;", "uniform float opacity;", + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "map_pars_fragment" ], THREE.ShaderChunk[ "lightmap_pars_fragment" ], @@ -21920,14 +23844,15 @@ THREE.ShaderLib = { "#endif", + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "map_pars_vertex" ], THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "envmap_pars_vertex" ], THREE.ShaderChunk[ "lights_lambert_pars_vertex" ], THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "lightattenuation_func_fragment" ], "void main() {", @@ -21945,7 +23870,6 @@ THREE.ShaderLib = { THREE.ShaderChunk[ "default_vertex" ], THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "envmap_vertex" ], THREE.ShaderChunk[ "lights_lambert_vertex" ], THREE.ShaderChunk[ "shadowmap_vertex" ], @@ -21965,6 +23889,7 @@ THREE.ShaderLib = { "#endif", + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "map_pars_fragment" ], THREE.ShaderChunk[ "lightmap_pars_fragment" ], @@ -22017,11 +23942,13 @@ THREE.ShaderLib = { uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "bump" ], + THREE.UniformsLib[ "bumpmap" ], THREE.UniformsLib[ "normalmap" ], + THREE.UniformsLib[ "specularmap" ], THREE.UniformsLib[ "fog" ], THREE.UniformsLib[ "lights" ], THREE.UniformsLib[ "shadowmap" ], + THREE.UniformsLib[ "opacitymap" ], { "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, @@ -22040,9 +23967,13 @@ THREE.ShaderLib = { "varying vec3 vViewPosition;", "varying vec3 vNormal;", + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "normalmap_pars_vertex" ], + THREE.ShaderChunk[ "bumpmap_pars_vertex" ], + THREE.ShaderChunk[ "specularmap_pars_vertex" ], + THREE.ShaderChunk[ "opacitymap_pars_vertex" ], THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "envmap_pars_vertex" ], THREE.ShaderChunk[ "lights_phong_pars_vertex" ], THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], @@ -22052,6 +23983,10 @@ THREE.ShaderLib = { "void main() {", THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "normalmap_vertex" ], + THREE.ShaderChunk[ "bumpmap_vertex" ], + THREE.ShaderChunk[ "opacitymap_vertex" ], + THREE.ShaderChunk[ "specularmap_vertex" ], THREE.ShaderChunk[ "lightmap_vertex" ], THREE.ShaderChunk[ "color_vertex" ], @@ -22069,7 +24004,6 @@ THREE.ShaderLib = { "vViewPosition = -mvPosition.xyz;", THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "envmap_vertex" ], THREE.ShaderChunk[ "lights_phong_vertex" ], THREE.ShaderChunk[ "shadowmap_vertex" ], @@ -22079,6 +24013,8 @@ THREE.ShaderLib = { fragmentShader: [ + "#define PHONG", + "uniform vec3 diffuse;", "uniform float opacity;", @@ -22087,8 +24023,10 @@ THREE.ShaderLib = { "uniform vec3 specular;", "uniform float shininess;", + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "opacitymap_pars_fragment" ], THREE.ShaderChunk[ "lightmap_pars_fragment" ], THREE.ShaderChunk[ "envmap_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], @@ -22097,12 +24035,15 @@ THREE.ShaderLib = { THREE.ShaderChunk[ "bumpmap_pars_fragment" ], THREE.ShaderChunk[ "normalmap_pars_fragment" ], THREE.ShaderChunk[ "specularmap_pars_fragment" ], + THREE.ShaderChunk[ "lightattenuation_func_fragment" ], "void main() {", "gl_FragColor = vec4( vec3 ( 1.0 ), opacity );", + "vec3 diffuseColor = diffuse;", THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "opacitymap_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "specularmap_fragment" ], @@ -22137,6 +24078,7 @@ THREE.ShaderLib = { "uniform float size;", "uniform float scale;", + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "shadowmap_pars_vertex" ], @@ -22166,6 +24108,7 @@ THREE.ShaderLib = { "uniform vec3 psColor;", "uniform float opacity;", + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "map_particle_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], @@ -22209,6 +24152,7 @@ THREE.ShaderLib = { "varying float vLineDistance;", + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_vertex" ], "void main() {", @@ -22234,6 +24178,7 @@ THREE.ShaderLib = { "varying float vLineDistance;", + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], @@ -22285,7 +24230,7 @@ THREE.ShaderLib = { "void main() {", "float depth = gl_FragCoord.z / gl_FragCoord.w;", - "float color = 1.0 - smoothstep( mNear, mFar, depth );", + "float color = clamp( ( depth - mNear ) / ( mFar - mNear ), 0.0, 1.0 );", "gl_FragColor = vec4( vec3( color ), opacity );", "}" @@ -22306,6 +24251,7 @@ THREE.ShaderLib = { "varying vec3 vNormal;", + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], "void main() {", @@ -22464,6 +24410,7 @@ THREE.ShaderLib = { "varying vec3 vWorldPosition;", "varying vec3 vViewPosition;", + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "shadowmap_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], @@ -22524,7 +24471,7 @@ THREE.ShaderLib = { "#endif", "vec3 normal = normalize( finalNormal );", - "vec3 viewPosition = normalize( vViewPosition );", + "vec3 viewDirection = normalize( vViewPosition );", // point lights @@ -22563,7 +24510,7 @@ THREE.ShaderLib = { // specular - "vec3 pointHalfVector = normalize( pointVector + viewPosition );", + "vec3 pointHalfVector = normalize( pointVector + viewDirection );", "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", "float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );", @@ -22621,7 +24568,7 @@ THREE.ShaderLib = { // specular - "vec3 spotHalfVector = normalize( spotVector + viewPosition );", + "vec3 spotHalfVector = normalize( spotVector + viewDirection );", "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", "float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, shininess ), 0.0 );", @@ -22669,7 +24616,7 @@ THREE.ShaderLib = { // specular - "vec3 dirHalfVector = normalize( dirVector + viewPosition );", + "vec3 dirHalfVector = normalize( dirVector + viewDirection );", "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", "float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, shininess ), 0.0 );", @@ -22708,7 +24655,7 @@ THREE.ShaderLib = { // specular (sky light) - "vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", + "vec3 hemiHalfVectorSky = normalize( lVector + viewDirection );", "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", "float hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", @@ -22716,7 +24663,7 @@ THREE.ShaderLib = { "vec3 lVectorGround = -lVector;", - "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", + "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewDirection );", "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", "float hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", @@ -22837,6 +24784,7 @@ THREE.ShaderLib = { "varying vec3 vWorldPosition;", "varying vec3 vViewPosition;", + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], THREE.ShaderChunk[ "shadowmap_pars_vertex" ], @@ -22952,7 +24900,10 @@ THREE.ShaderLib = { 'cube': { uniforms: { "tCube": { type: "t", value: null }, - "tFlip": { type: "f", value: -1 } }, + "tFlip": { type: "f", value: -1 }, + "tEncoding": { type: "i", value: 0 }, + "blurring": { type: "f", value: 0 } + }, vertexShader: [ @@ -22971,16 +24922,44 @@ THREE.ShaderLib = { fragmentShader: [ - "uniform samplerCube tCube;", - "uniform float tFlip;", + "#ifdef TEXTURE_CUBE_LOD_EXT", + "#extension GL_EXT_shader_texture_lod : enable", + "#endif", - "varying vec3 vWorldPosition;", + THREE.ShaderChunk[ "common" ], - "void main() {", + "uniform samplerCube tCube;", + "uniform float tFlip;", + "uniform int tEncoding;", + "uniform float blurring;", - "gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", + "varying vec3 vWorldPosition;", - "}" + "void main() {", + + "vec3 queryVector = vec3( tFlip * vWorldPosition.x, vWorldPosition.yz );", + + "#if defined( TEXTURE_CUBE_LOD_EXT )", + + "vec4 color = textureCubeLodEXT( tCube, queryVector, blurring );", + + "#else", + + "vec4 color = textureCube( tCube, queryVector );", + + "#endif", + + "color = texelDecode( color, tEncoding );", + + "#ifdef GAMMA_OUTPUT", + + "color.xyz = sqrt( color.xyz );", + + "#endif", + + "gl_FragColor = color;", + + "}" ].join("\n") @@ -23000,6 +24979,7 @@ THREE.ShaderLib = { vertexShader: [ + THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], @@ -23016,13 +24996,13 @@ THREE.ShaderLib = { fragmentShader: [ - "vec4 pack_depth( const in float depth ) {", + "vec4 pack_depth( const float depth ) {", - "const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", - "const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", - "vec4 res = fract( depth * bit_shift );", - "res -= res.xxyz * bit_mask;", - "return res;", + " const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", + " const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", + " vec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );", // " vec4 res = fract( depth * bit_shift );", + " res -= res.xxyz * bit_mask;", + " return res;", "}", @@ -23039,14 +25019,84 @@ THREE.ShaderLib = { ].join("\n") + }, + + // Depth encoding into RGBA texture + // based on SpiderGL shadow map example + // http://spidergl.org/example.php?id=6 + // originally from + // http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD + // see also here: + // http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ + + 'linearDepthRGBA': { + + uniforms: { + "zNear": { type: "f", value: 0.5 }, + "zFar": { type: "f", value: 1000 } + }, + + vertexShader: [ + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + + "varying vec3 vViewPosition;", + + "void main() {", + + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + + "vViewPosition = -mvPosition.xyz;", + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform float zNear;", + "uniform float zFar;", + + "varying vec3 vViewPosition;", + + "vec4 pack_depth( const float depth ) {", + + " const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", + " const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", + " vec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );", // " vec4 res = fract( depth * bit_shift );", + " res -= res.xxyz * bit_mask;", + " return res;", + + "}", + + "void main() {", + + "gl_FragColor = pack_depth( clamp( ( vViewPosition.z - zNear ) / ( zFar - zNear ), 0.0, 1.0 ) );", + + //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );", + //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );", + //"gl_FragData[ 0 ] = pack_depth( z );", + //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", + + "}" + + ].join("\n") + } }; + /** * @author supereggbert / http://www.paulbrunt.co.uk/ * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author szimek / https://github.com/szimek/ + * @author bhouston / http://clara.io/ */ THREE.WebGLRenderer = function ( parameters ) { @@ -23058,7 +25108,7 @@ THREE.WebGLRenderer = function ( parameters ) { var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), _context = parameters.context !== undefined ? parameters.context : null, - _precision = parameters.precision !== undefined ? parameters.precision : 'highp', + _precision = parameters.precision !== undefined ? parameters.precision : 'mediump', _buffers = {}, @@ -23095,8 +25145,8 @@ THREE.WebGLRenderer = function ( parameters ) { // physically based shading - this.gammaInput = false; - this.gammaOutput = false; + this.gammaInput = true; + this.gammaOutput = true; // shadow map @@ -23200,6 +25250,8 @@ THREE.WebGLRenderer = function ( parameters ) { _projScreenMatrixPS = new THREE.Matrix4(), _vector3 = new THREE.Vector3(), + _width = new THREE.Vector3(), + _height = new THREE.Vector3(), // light arrays cache @@ -23211,9 +25263,10 @@ THREE.WebGLRenderer = function ( parameters ) { ambient: [ 0, 0, 0 ], directional: { length: 0, colors: new Array(), positions: new Array() }, - point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array() }, - spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), directions: new Array(), anglesCos: new Array(), exponents: new Array() }, - hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() } + point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), decayExponents: new Array() }, + spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), decayExponents: new Array(), directions: new Array(), anglesCos: new Array(), exponents: new Array() }, + hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() }, + area: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), decayExponents: new Array(), widths: new Array(), heights: new Array() } }; @@ -23224,6 +25277,7 @@ THREE.WebGLRenderer = function ( parameters ) { var _glExtensionTextureFloat; var _glExtensionTextureFloatLinear; var _glExtensionStandardDerivatives; + var _glExtensionShaderTextureLOD; var _glExtensionTextureFilterAnisotropic; var _glExtensionCompressedTextureS3TC; @@ -23275,12 +25329,12 @@ THREE.WebGLRenderer = function ( parameters ) { if ( mediumpAvailable ) { _precision = "mediump"; - console.warn( "WebGLRenderer: highp not supported, using mediump" ); + THREE.onwarning( "WebGLRenderer: highp not supported, using mediump" ); } else { _precision = "lowp"; - console.warn( "WebGLRenderer: highp and mediump not supported, using lowp" ); + THREE.onwarning( "WebGLRenderer: highp and mediump not supported, using lowp" ); } @@ -23289,7 +25343,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( _precision === "mediump" && ! mediumpAvailable ) { _precision = "lowp"; - console.warn( "WebGLRenderer: mediump not supported, using lowp" ); + THREE.onwarning( "WebGLRenderer: mediump not supported, using lowp" ); } @@ -23395,7 +25449,7 @@ THREE.WebGLRenderer = function ( parameters ) { this.setClearColorHex = function ( hex, alpha ) { - console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); + THREE.onwarning( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); this.setClearColor( hex, alpha ); }; @@ -23645,7 +25699,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attributes[ key ].buffer !== undefined ) { _gl.deleteBuffer( attributes[ key ].buffer ); - + } } @@ -23739,13 +25793,15 @@ THREE.WebGLRenderer = function ( parameters ) { }; - var deallocateMaterial = function ( material ) { + var deallocateMaterial = function ( material, optionalDisconnectedProgram ) { - var program = material.program; + var program = optionalDisconnectedProgram || material.program; if ( program === undefined ) return; - material.program = undefined; + if( ! optionalDisconnectedProgram ) { + material.program = undefined; + } // only deallocate GL program if this was the last use of shared program // assumed there is only single copy of any program in the _programs list @@ -23896,8 +25952,6 @@ THREE.WebGLRenderer = function ( parameters ) { normalType = bufferGuessNormalType( material ), vertexColorType = bufferGuessVertexColorType( material ); - // console.log( "uvType", uvType, "normalType", normalType, "vertexColorType", vertexColorType, object, geometryGroup, material ); - geometryGroup.__vertexArray = new Float32Array( nvertices * 3 ); if ( normalType ) { @@ -24085,17 +26139,27 @@ THREE.WebGLRenderer = function ( parameters ) { // material must use some texture to require uvs if ( material.map || + material.opacityMap || material.lightMap || + material.emissiveMap || material.bumpMap || material.normalMap || material.specularMap || + material.reflectivityMap || + material.roughnessMap || + material.falloffMap || + material.anisotropyMap || + material.anisotropyRotationMap || + material.metallicMap || + material.translucencyMap || + ( material.anisotropy && material.anisotropy !== 0.0 ) || material instanceof THREE.ShaderMaterial ) { return true; } - return false; + return true; }; @@ -24947,15 +27011,17 @@ THREE.WebGLRenderer = function ( parameters ) { if ( dirtyTangents && geometry.hasTangents ) { + var tmp = new THREE.Vector3( 0, 0, 0 ); + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { face = obj_faces[ chunk_faces3[ f ] ]; vertexTangents = face.vertexTangents; - t1 = vertexTangents[ 0 ]; - t2 = vertexTangents[ 1 ]; - t3 = vertexTangents[ 2 ]; + t1 = vertexTangents[ 0 ] || tmp; + t2 = vertexTangents[ 1 ] || tmp; + t3 = vertexTangents[ 2 ] || tmp; tangentArray[ offset_tangent ] = t1.x; tangentArray[ offset_tangent + 1 ] = t1.y; @@ -25436,7 +27502,7 @@ THREE.WebGLRenderer = function ( parameters ) { attributePointer = programAttributes[ attributeName ]; attributeItem = geometryAttributes[ attributeName ]; - + if ( attributePointer >= 0 ) { if ( attributeItem ) { @@ -25706,7 +27772,7 @@ THREE.WebGLRenderer = function ( parameters ) { attributePointer = programAttributes[ attributeName ]; attributeItem = geometryAttributes[ attributeName ]; - + if ( attributePointer >= 0 ) { if ( attributeItem ) { @@ -25758,7 +27824,7 @@ THREE.WebGLRenderer = function ( parameters ) { attributePointer = programAttributes[ attributeName ]; attributeItem = geometryAttributes[ attributeName ]; - + if ( attributePointer >= 0 ) { if ( attributeItem ) { @@ -25806,7 +27872,7 @@ THREE.WebGLRenderer = function ( parameters ) { var index = geometryAttributes[ "index" ]; // indexed lines - + if ( index ) { var offsets = geometry.offsets; @@ -25970,7 +28036,6 @@ THREE.WebGLRenderer = function ( parameters ) { // tangents if ( attributes.tangent >= 0 ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); enableAttribute( attributes.tangent ); _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); @@ -26289,7 +28354,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( camera instanceof THREE.Camera === false ) { - console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + THREE.onerror( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); return; } @@ -26450,7 +28515,9 @@ THREE.WebGLRenderer = function ( parameters ) { // Generate mipmap if we're using any kind of mipmap filtering - if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) { + if ( renderTarget && renderTarget.generateMipmaps && + renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter && + THREE.isPowerOfTwo( renderTarget.width ) && THREE.isPowerOfTwo( renderTarget.height ) ) { updateRenderTargetMipmap( renderTarget ); @@ -26805,6 +28872,7 @@ THREE.WebGLRenderer = function ( parameters ) { geometry.uvsNeedUpdate = true; geometry.normalsNeedUpdate = true; geometry.tangentsNeedUpdate = true; + geometry.colorsNeedUpdate = true; } @@ -27116,6 +29184,10 @@ THREE.WebGLRenderer = function ( parameters ) { shaderID = 'phong'; + } else if ( material instanceof THREE.MeshPhysicalMaterial ) { + + shaderID = 'physical'; + } else if ( material instanceof THREE.LineBasicMaterial ) { shaderID = 'basic'; @@ -27130,12 +29202,16 @@ THREE.WebGLRenderer = function ( parameters ) { } - if ( shaderID ) { + if ( shaderID && THREE.ShaderLib[ shaderID ] ) { setMaterialShaders( material, THREE.ShaderLib[ shaderID ] ); } + if( ! shaderID ) { + shaderID = material.shaderID; + } + // heuristics to create shader parameters according to lights in the scene // (not to blow over maxLights budget) @@ -27148,11 +29224,26 @@ THREE.WebGLRenderer = function ( parameters ) { parameters = { map: !!material.map, + opacityMap: !!material.opacityMap, envMap: !!material.envMap, + diffuseEnvMap: !!material.diffuseEnvMap, lightMap: !!material.lightMap, + emissiveMap: !!material.emissiveMap, bumpMap: !!material.bumpMap, normalMap: !!material.normalMap, specularMap: !!material.specularMap, + reflectivityMap: !!material.reflectivityMap, + roughnessMap: !!material.roughnessMap, + translucencyMap: !!material.translucencyMap, + metallicMap: !!material.metallicMap, + falloffMap: !!material.falloffMap, + + clearCoat: (( material.clearCoat !== undefined )&&( material.clearCoat !== 0 )), + + anisotropy: (( material.anisotropy !== undefined )&&( material.anisotropy !== 0 ))||( !! material.anisotropyMap ), + anisotropyMap: !! material.anisotropyMap, + anisotropyRotation: (( material.anisotropyRotation !== undefined )&&( material.anisotropyRotation !== 0 ))||( !! material.anisotropyRotationMap ), + anisotropyRotationMap: !! material.anisotropyRotationMap, vertexColors: material.vertexColors, @@ -27160,7 +29251,7 @@ THREE.WebGLRenderer = function ( parameters ) { useFog: material.fog, fogExp: fog instanceof THREE.FogExp2, - sizeAttenuation: material.sizeAttenuation, + sizeAttenuation: !! material.sizeAttenuation, skinning: material.skinning, maxBones: maxBones, @@ -27175,6 +29266,7 @@ THREE.WebGLRenderer = function ( parameters ) { maxPointLights: maxLightCount.point, maxSpotLights: maxLightCount.spot, maxHemiLights: maxLightCount.hemi, + maxAreaLights: maxLightCount.area, maxShadows: maxShadows, shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow && maxShadows > 0, @@ -27182,8 +29274,10 @@ THREE.WebGLRenderer = function ( parameters ) { shadowMapDebug: this.shadowMapDebug, shadowMapCascade: this.shadowMapCascade, + translucency: material.translucency && ( material.translucency.getHex() > 0 ), + alphaTest: material.alphaTest, - metal: material.metal, + falloff: ( material.falloff || false ), wrapAround: material.wrapAround, doubleSided: material.side === THREE.DoubleSide, flipSided: material.side === THREE.BackSide @@ -27258,11 +29352,14 @@ THREE.WebGLRenderer = function ( parameters ) { if ( material.needsUpdate ) { - if ( material.program ) deallocateMaterial( material ); + var oldProgram = material.program; _this.initMaterial( material, lights, fog, object ); material.needsUpdate = false; + if ( oldProgram ) deallocateMaterial( material, oldProgram ); + + } if ( material.morphTargets ) { @@ -27358,6 +29455,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( material instanceof THREE.MeshPhongMaterial || material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshPhysicalMaterial || material.lights ) { if ( _lightsNeedUpdate ) { @@ -27373,6 +29471,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshPhysicalMaterial || material instanceof THREE.MeshPhongMaterial ) { refreshUniformsCommon( m_uniforms, material ); @@ -27398,6 +29497,10 @@ THREE.WebGLRenderer = function ( parameters ) { refreshUniformsPhong( m_uniforms, material ); + } else if ( material instanceof THREE.MeshPhysicalMaterial ) { + + refreshUniformsPhysical( m_uniforms, material ); + } else if ( material instanceof THREE.MeshLambertMaterial ) { refreshUniformsLambert( m_uniforms, material ); @@ -27429,7 +29532,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( material instanceof THREE.ShaderMaterial || material instanceof THREE.MeshPhongMaterial || - material.envMap ) { + material instanceof THREE.MeshPhysicalMaterial || + material.envMap || + material.diffuseEnvMap ) { if ( p_uniforms.cameraPosition !== null ) { @@ -27442,6 +29547,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( material instanceof THREE.MeshPhongMaterial || material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshPhysicalMaterial || material instanceof THREE.ShaderMaterial || material.skinning ) { @@ -27473,19 +29579,11 @@ THREE.WebGLRenderer = function ( parameters ) { uniforms.opacity.value = material.opacity; - if ( _this.gammaInput ) { - - uniforms.diffuse.value.copyGammaToLinear( material.color ); - - } else { - - uniforms.diffuse.value = material.color; - - } + uniforms.diffuse.value = material.color; uniforms.map.value = material.map; uniforms.lightMap.value = material.lightMap; - uniforms.specularMap.value = material.specularMap; + uniforms.emissiveMap.value = material.emissiveMap; if ( material.bumpMap ) { @@ -27501,55 +29599,96 @@ THREE.WebGLRenderer = function ( parameters ) { } - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. normal map - // 4. bump map + if ( material.map ) { - var uvScaleMap; + var map = material.map; + uniforms.offsetRepeat.value.set( map.offset.x, map.offset.y, map.repeat.x, map.repeat.y ); + uniforms.gainBrightness.value.set( map.gainPivot, map.gain, map.brightness, map.invert ? -1.0 : 1.0 ); - if ( material.map ) { + } - uvScaleMap = material.map; + if ( material.specularMap ) { - } else if ( material.specularMap ) { + var specularMap = material.specularMap; + uniforms.specularMap.value = specularMap; + uniforms.specularOffsetRepeat.value.set( specularMap.offset.x, specularMap.offset.y, specularMap.repeat.x, specularMap.repeat.y ); + uniforms.specularGainBrightness.value.set( specularMap.gainPivot, specularMap.gain, specularMap.brightness, specularMap.invert ? -1.0 : 1.0 ); - uvScaleMap = material.specularMap; + } - } else if ( material.normalMap ) { + if ( material.opacityMap ) { - uvScaleMap = material.normalMap; + var opacityMap = material.opacityMap; + uniforms.opacityMap.value = opacityMap; + uniforms.opacityOffsetRepeat.value.set( opacityMap.offset.x, opacityMap.offset.y, opacityMap.repeat.x, opacityMap.repeat.y ); + uniforms.opacityGainBrightness.value.set( opacityMap.gainPivot, opacityMap.gain, opacityMap.brightness, opacityMap.invert ? -1.0 : 1.0 ); - } else if ( material.bumpMap ) { + } + + if ( material.bumpMap ) { - uvScaleMap = material.bumpMap; + var bumpMap = material.bumpMap; + uniforms.bumpOffsetRepeat.value.set( bumpMap.offset.x, bumpMap.offset.y, bumpMap.repeat.x, bumpMap.repeat.y ); + //uniforms.bumpGainBrightness.value.set( bumpMap.gainPivot, bumpMap.gain, bumpMap.brightness, 1.0 ); } - if ( uvScaleMap !== undefined ) { + if ( material.normalMap ) { + + var normalMap = material.normalMap; + uniforms.normalOffsetRepeat.value.set( normalMap.offset.x, normalMap.offset.y, normalMap.repeat.x, normalMap.repeat.y ); + //uniforms.normalGainBrightness.value.set( normalMap.gainPivot, normalMap.gain, normalMap.brightness, 1.0 ); + + } - var offset = uvScaleMap.offset; - var repeat = uvScaleMap.repeat; + if ( material.anisotropyMap ) { - uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); + var anisotropyMap = material.anisotropyMap; + uniforms.anisotropyOffsetRepeat.value.set( anisotropyMap.offset.x, anisotropyMap.offset.y, anisotropyMap.repeat.x, anisotropyMap.repeat.y ); + uniforms.anisotropyGainBrightness.value.set( anisotropyMap.gainPivot, anisotropyMap.gain, anisotropyMap.brightness, anisotropyMap.invert ? -1.0 : 1.0 ); } - uniforms.envMap.value = material.envMap; - uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1; + if ( material.anisotropyRotationMap ) { - if ( _this.gammaInput ) { + var anisotropyRotationMap = material.anisotropyRotationMap; + uniforms.anisotropyRotationOffsetRepeat.value.set( anisotropyRotationMap.offset.x, anisotropyRotationMap.offset.y, anisotropyRotationMap.repeat.x, anisotropyRotationMap.repeat.y ); + uniforms.anisotropyRotationGainBrightness.value.set( anisotropyRotationMap.gainPivot, anisotropyRotationMap.gain, anisotropyRotationMap.brightness, anisotropyRotationMap.invert ? -1.0 : 1.0 ); - //uniforms.reflectivity.value = material.reflectivity * material.reflectivity; - uniforms.reflectivity.value = material.reflectivity; + } - } else { + if ( material.roughnessMap ) { - uniforms.reflectivity.value = material.reflectivity; + var roughnessMap = material.roughnessMap; + uniforms.roughnessOffsetRepeat.value.set( roughnessMap.offset.x, roughnessMap.offset.y, roughnessMap.repeat.x, roughnessMap.repeat.y ); + uniforms.roughnessGainBrightness.value.set( roughnessMap.gainPivot, roughnessMap.gain, roughnessMap.brightness, roughnessMap.invert ? -1.0 : 1.0 ); } + if ( material.metallicMap ) { + + var metallicMap = material.metallicMap; + uniforms.metallicOffsetRepeat.value.set( metallicMap.offset.x, metallicMap.offset.y, metallicMap.repeat.x, metallicMap.repeat.y ); + uniforms.metallicGainBrightness.value.set( metallicMap.gainPivot, metallicMap.gain, metallicMap.brightness, metallicMap.invert ? -1.0 : 1.0 ); + + } + + if ( material.translucencyMap ) { + + var translucencyMap = material.translucencyMap; + uniforms.translucencyMap.value = translucencyMap; + //uniforms.translucencyOffsetRepeat.value.set( translucencyMap.offset.x, translucencyMap.offset.y, translucencyMap.repeat.x, translucencyMap.repeat.y ); + //uniforms.translucencyGainBrightness.value.set( translucencyMap.gainPivot, translucencyMap.gain, translucencyMap.brightness, 1.0 ); + + } + uniforms.envMap.value = material.envMap; + uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1; + uniforms.envEncoding.value = ( material.envMap ) ? material.envMap.encoding : 0; + uniforms.diffuseEnvMap.value = material.diffuseEnvMap; + uniforms.diffuseEnvEncoding.value = ( material.diffuseEnvMap ) ? material.diffuseEnvMap.encoding : 0; + + uniforms.reflectivity.value = material.reflectivity; + uniforms.refractionRatio.value = material.refractionRatio; uniforms.combine.value = material.combine; uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping; @@ -27601,21 +29740,13 @@ THREE.WebGLRenderer = function ( parameters ) { function refreshUniformsPhong ( uniforms, material ) { - uniforms.shininess.value = material.shininess; - - if ( _this.gammaInput ) { + uniforms.opacityMap.value = material.opacityMap; - uniforms.ambient.value.copyGammaToLinear( material.ambient ); - uniforms.emissive.value.copyGammaToLinear( material.emissive ); - uniforms.specular.value.copyGammaToLinear( material.specular ); - - } else { - - uniforms.ambient.value = material.ambient; - uniforms.emissive.value = material.emissive; - uniforms.specular.value = material.specular; + uniforms.shininess.value = material.shininess; - } + uniforms.ambient.value = material.ambient; + uniforms.emissive.value = material.emissive; + uniforms.specular.value = material.specular; if ( material.wrapAround ) { @@ -27625,19 +29756,45 @@ THREE.WebGLRenderer = function ( parameters ) { }; - function refreshUniformsLambert ( uniforms, material ) { + function refreshUniformsPhysical ( uniforms, material ) { - if ( _this.gammaInput ) { + uniforms.opacityMap.value = material.opacityMap; - uniforms.ambient.value.copyGammaToLinear( material.ambient ); - uniforms.emissive.value.copyGammaToLinear( material.emissive ); + uniforms.falloffBlendParams.value = material.falloffBlendParams; + uniforms.falloffMap.value = material.falloffMap; - } else { + uniforms.roughness.value = material.roughness; + uniforms.metallic.value = material.metallic; - uniforms.ambient.value = material.ambient; - uniforms.emissive.value = material.emissive; + uniforms.clearCoat.value = material.clearCoat; + uniforms.clearCoatRoughness.value = material.clearCoatRoughness; - } + uniforms.roughnessMap.value = material.roughnessMap; + uniforms.metallicMap.value = material.metallicMap; + + uniforms.translucencyMap.value = material.translucencyMap; + uniforms.translucencyNormalAlpha.value = material.translucencyNormalAlpha; + uniforms.translucencyNormalPower.value = material.translucencyNormalPower; + uniforms.translucencyViewAlpha.value = material.translucencyViewAlpha; + uniforms.translucencyViewPower.value = material.translucencyViewPower; + + uniforms.anisotropyMap.value = material.anisotropyMap; + uniforms.anisotropy.value = material.anisotropy; + uniforms.anisotropyRotation.value = material.anisotropyRotation; + uniforms.anisotropyRotationMap.value = material.anisotropyRotationMap; + + uniforms.ambient.value = material.ambient; + uniforms.emissive.value = material.emissive; + uniforms.falloffColor.value = material.falloffColor; + uniforms.specular.value = material.specular; + uniforms.translucency.value = material.translucency; + + }; + + function refreshUniformsLambert ( uniforms, material ) { + + uniforms.ambient.value = material.ambient; + uniforms.emissive.value = material.emissive; if ( material.wrapAround ) { @@ -27657,10 +29814,12 @@ THREE.WebGLRenderer = function ( parameters ) { uniforms.pointLightColor.value = lights.point.colors; uniforms.pointLightPosition.value = lights.point.positions; uniforms.pointLightDistance.value = lights.point.distances; + uniforms.pointLightDecayExponent.value = lights.point.decayExponents; uniforms.spotLightColor.value = lights.spot.colors; uniforms.spotLightPosition.value = lights.spot.positions; uniforms.spotLightDistance.value = lights.spot.distances; + uniforms.spotLightDecayExponent.value = lights.spot.decayExponents; uniforms.spotLightDirection.value = lights.spot.directions; uniforms.spotLightAngleCos.value = lights.spot.anglesCos; uniforms.spotLightExponent.value = lights.spot.exponents; @@ -27669,6 +29828,13 @@ THREE.WebGLRenderer = function ( parameters ) { uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; uniforms.hemisphereLightDirection.value = lights.hemi.positions; + uniforms.areaLightColor.value = lights.area.colors; + uniforms.areaLightPosition.value = lights.area.positions; + uniforms.areaLightDistance.value = lights.area.distances; + uniforms.areaLightDecayExponent.value = lights.area.decayExponents; + uniforms.areaLightWidth.value = lights.area.widths; + uniforms.areaLightHeight.value = lights.area.heights; + }; function refreshUniformsShadow ( uniforms, lights ) { @@ -27723,7 +29889,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( textureUnit >= _maxTextures ) { - console.warn( "WebGLRenderer: trying to use " + textureUnit + " texture units while this GPU supports only " + _maxTextures ); + THREE.onwarning( "WebGLRenderer: trying to use " + textureUnit + " texture units while this GPU supports only " + _maxTextures ); } @@ -27926,7 +30092,7 @@ THREE.WebGLRenderer = function ( parameters ) { } else { - console.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); + THREE.onwarning( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); } @@ -27943,13 +30109,6 @@ THREE.WebGLRenderer = function ( parameters ) { // - function setColorGamma( array, offset, color, intensitySq ) { - - array[ offset ] = color.r * color.r * intensitySq; - array[ offset + 1 ] = color.g * color.g * intensitySq; - array[ offset + 2 ] = color.b * color.b * intensitySq; - - }; function setColorLinear( array, offset, color, intensity ) { @@ -27976,10 +30135,12 @@ THREE.WebGLRenderer = function ( parameters ) { pointColors = zlights.point.colors, pointPositions = zlights.point.positions, pointDistances = zlights.point.distances, + pointDecayExponents = zlights.point.decayExponents, spotColors = zlights.spot.colors, spotPositions = zlights.spot.positions, spotDistances = zlights.spot.distances, + spotDecayExponents = zlights.spot.decayExponents, spotDirections = zlights.spot.directions, spotAnglesCos = zlights.spot.anglesCos, spotExponents = zlights.spot.exponents, @@ -27988,20 +30149,30 @@ THREE.WebGLRenderer = function ( parameters ) { hemiGroundColors = zlights.hemi.groundColors, hemiPositions = zlights.hemi.positions, + areaColors = zlights.area.colors, + areaPositions = zlights.area.positions, + areaDistances = zlights.area.distances, + areaDecayExponents = zlights.area.decayExponents, + areaWidths = zlights.area.widths, + areaHeights = zlights.area.heights, + dirLength = 0, pointLength = 0, spotLength = 0, hemiLength = 0, + areaLength = 0, dirCount = 0, pointCount = 0, spotCount = 0, hemiCount = 0, + areaCount = 0, dirOffset = 0, pointOffset = 0, spotOffset = 0, - hemiOffset = 0; + hemiOffset = 0, + areaOffset = 0; for ( l = 0, ll = lights.length; l < ll; l ++ ) { @@ -28017,19 +30188,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( ! light.visible ) continue; - if ( _this.gammaInput ) { - - r += color.r * color.r; - g += color.g * color.g; - b += color.b * color.b; - - } else { - - r += color.r; - g += color.g; - b += color.b; - - } + r += color.r; + g += color.g; + b += color.b; } else if ( light instanceof THREE.DirectionalLight ) { @@ -28053,15 +30214,8 @@ THREE.WebGLRenderer = function ( parameters ) { dirPositions[ dirOffset + 1 ] = _direction.y; dirPositions[ dirOffset + 2 ] = _direction.z; - if ( _this.gammaInput ) { - setColorGamma( dirColors, dirOffset, color, intensity * intensity ); - - } else { - - setColorLinear( dirColors, dirOffset, color, intensity ); - - } + setColorLinear( dirColors, dirOffset, color, intensity ); dirLength += 1; @@ -28073,15 +30227,7 @@ THREE.WebGLRenderer = function ( parameters ) { pointOffset = pointLength * 3; - if ( _this.gammaInput ) { - - setColorGamma( pointColors, pointOffset, color, intensity * intensity ); - - } else { - - setColorLinear( pointColors, pointOffset, color, intensity ); - - } + setColorLinear( pointColors, pointOffset, color, intensity ); _vector3.setFromMatrixPosition( light.matrixWorld ); @@ -28091,6 +30237,14 @@ THREE.WebGLRenderer = function ( parameters ) { pointDistances[ pointLength ] = distance; + if( light.physicalFalloff ) { + // magic value of -1 switches the equation to UE4 physical quadratic falloff. + pointDecayExponents[ pointLength ] = -1.0; + } + else { + pointDecayExponents[ pointLength ] = ( distance === 0 ) ? 0.0 : light.decayExponent; + } + pointLength += 1; } else if ( light instanceof THREE.SpotLight ) { @@ -28101,15 +30255,7 @@ THREE.WebGLRenderer = function ( parameters ) { spotOffset = spotLength * 3; - if ( _this.gammaInput ) { - - setColorGamma( spotColors, spotOffset, color, intensity * intensity ); - - } else { - - setColorLinear( spotColors, spotOffset, color, intensity ); - - } + setColorLinear( spotColors, spotOffset, color, intensity ); _vector3.setFromMatrixPosition( light.matrixWorld ); @@ -28119,6 +30265,14 @@ THREE.WebGLRenderer = function ( parameters ) { spotDistances[ spotLength ] = distance; + if( light.physicalFalloff ) { + // magic value of -1 switches the equation to UE4 physical quadratic falloff. + spotDecayExponents[ pointLength ] = -1.0; + } + else { + spotDecayExponents[ pointLength ] = ( distance === 0 ) ? 0.0 : light.decayExponent; + } + _direction.copy( _vector3 ); _vector3.setFromMatrixPosition( light.target.matrixWorld ); _direction.sub( _vector3 ); @@ -28156,21 +30310,43 @@ THREE.WebGLRenderer = function ( parameters ) { skyColor = light.color; groundColor = light.groundColor; - if ( _this.gammaInput ) { + setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); + setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); - intensitySq = intensity * intensity; + hemiLength += 1; - setColorGamma( hemiSkyColors, hemiOffset, skyColor, intensitySq ); - setColorGamma( hemiGroundColors, hemiOffset, groundColor, intensitySq ); + } else if ( light instanceof THREE.AreaLight ) { - } else { + areaCount += 1; - setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); - setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); + if ( ! light.visible ) continue; - } + areaOffset = areaLength * 3; - hemiLength += 1; + setColorLinear( areaColors, areaOffset, color, intensity ); + + _vector3.setFromMatrixPosition( light.matrixWorld ); + + areaPositions[ areaOffset ] = _vector3.x; + areaPositions[ areaOffset + 1 ] = _vector3.y; + areaPositions[ areaOffset + 2 ] = _vector3.z; + + areaDistances[ areaLength ] = distance; + areaDecayExponents[ areaLength ] = light.decayExponent; + + light.matrixWorld.extractBasis( _width, _height, _vector3 ); + _width.multiplyScalar( light.width ); + _height.multiplyScalar( light.height ); + + areaWidths[ areaOffset ] = _width.x; + areaWidths[ areaOffset + 1 ] = _width.y; + areaWidths[ areaOffset + 2 ] = _width.z; + + areaHeights[ areaOffset ] = _height.x; + areaHeights[ areaOffset + 1 ] = _height.y; + areaHeights[ areaOffset + 2 ] = _height.z; + + areaLength += 1; } @@ -28184,11 +30360,13 @@ THREE.WebGLRenderer = function ( parameters ) { for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0; for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0; for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0; + for ( l = areaLength * 3, ll = Math.max( areaColors.length, areaCount * 3 ); l < ll; l ++ ) areaColors[ l ] = 0.0; zlights.directional.length = dirLength; zlights.point.length = pointLength; zlights.spot.length = spotLength; zlights.hemi.length = hemiLength; + zlights.area.length = areaLength; zlights.ambient[ 0 ] = r; zlights.ambient[ 1 ] = g; @@ -28445,6 +30623,7 @@ THREE.WebGLRenderer = function ( parameters ) { function buildProgram( shaderID, fragmentShader, vertexShader, uniforms, attributes, defines, parameters, index0AttributeName ) { var p, pl, d, program, code; + var simpleChunks = []; var chunks = []; // Generate code @@ -28452,6 +30631,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( shaderID ) { chunks.push( shaderID ); + simpleChunks.push( shaderID ); } else { @@ -28464,6 +30644,8 @@ THREE.WebGLRenderer = function ( parameters ) { chunks.push( d ); chunks.push( defines[ d ] ); + simpleChunks.push( d ); + simpleChunks.push( defines[ d ] ); } @@ -28472,9 +30654,13 @@ THREE.WebGLRenderer = function ( parameters ) { chunks.push( p ); chunks.push( parameters[ p ] ); + simpleChunks.push( p ); + simpleChunks.push( parameters[ p ] ); + } code = chunks.join(); + var simpleCode = simpleChunks.join(); // Check if code has been already compiled @@ -28482,9 +30668,7 @@ THREE.WebGLRenderer = function ( parameters ) { var programInfo = _programs[ p ]; - if ( programInfo.code === code ) { - - // console.log( "Code already compiled." /*: \n\n" + code*/ ); + if ( programInfo.code.length === code.length && programInfo.code === code ) { programInfo.usedTimes ++; @@ -28506,16 +30690,12 @@ THREE.WebGLRenderer = function ( parameters ) { } - // console.log( "building new program " ); - - // - var customDefines = generateDefines( defines ); - // - program = _gl.createProgram(); + var supportsShaderTextureLOD = ( _glExtensionShaderTextureLOD !== null ); + var prefix_vertex = [ "precision " + _precision + " float;", @@ -28532,18 +30712,33 @@ THREE.WebGLRenderer = function ( parameters ) { "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, + "#define MAX_AREA_LIGHTS " + parameters.maxAreaLights, "#define MAX_SHADOWS " + parameters.maxShadows, "#define MAX_BONES " + parameters.maxBones, parameters.map ? "#define USE_MAP" : "", + parameters.opacityMap ? "#define USE_OPACITYMAP" : "", + parameters.falloffMap ? "#define USE_FALLOFFMAP" : "", + parameters.translucencyMap ? "#define USE_TRANSLUCENCYMAP" : "", parameters.envMap ? "#define USE_ENVMAP" : "", + parameters.diffuseEnvMap ? "#define USE_DIFFUSEENVMAP" : "", parameters.lightMap ? "#define USE_LIGHTMAP" : "", + parameters.emissiveMap ? "#define USE_EMISSIVEMAP" : "", parameters.bumpMap ? "#define USE_BUMPMAP" : "", + parameters.reflectivityMap ? "#define USE_REFLECTIVITYMAP" : "", + parameters.roughnessMap ? "#define USE_ROUGHNESSMAP" : "", + parameters.metallicMap ? "#define USE_METALLICMAP" : "", parameters.normalMap ? "#define USE_NORMALMAP" : "", parameters.specularMap ? "#define USE_SPECULARMAP" : "", parameters.vertexColors ? "#define USE_COLOR" : "", + parameters.clearCoat ? "#define CLEARCOAT" : "", + + parameters.anisotropy ? "#define ANISOTROPY" : "", + parameters.anisotropyMap ? "#define USE_ANISOTROPYMAP" : "", + ( parameters.anisotropy && parameters.anisotropyRotation ) ? "#define ANISOTROPYROTATION" : "", + ( parameters.anisotropy && parameters.anisotropyRotationMap ) ? "#define USE_ANISOTROPYROTATIONMAP" : "", parameters.skinning ? "#define USE_SKINNING" : "", parameters.useVertexTexture ? "#define BONE_TEXTURE" : "", @@ -28615,6 +30810,7 @@ THREE.WebGLRenderer = function ( parameters ) { ].join("\n"); + var prefix_fragment = [ "precision " + _precision + " float;", @@ -28628,6 +30824,7 @@ THREE.WebGLRenderer = function ( parameters ) { "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, + "#define MAX_AREA_LIGHTS " + parameters.maxAreaLights, "#define MAX_SHADOWS " + parameters.maxShadows, @@ -28640,14 +30837,31 @@ THREE.WebGLRenderer = function ( parameters ) { ( parameters.useFog && parameters.fogExp ) ? "#define FOG_EXP2" : "", parameters.map ? "#define USE_MAP" : "", + parameters.opacityMap ? "#define USE_OPACITYMAP" : "", + parameters.falloffMap ? "#define USE_FALLOFFMAP" : "", + parameters.translucencyMap ? "#define USE_TRANSLUCENCYMAP" : "", parameters.envMap ? "#define USE_ENVMAP" : "", + parameters.diffuseEnvMap ? "#define USE_DIFFUSEENVMAP" : "", parameters.lightMap ? "#define USE_LIGHTMAP" : "", + parameters.emissiveMap ? "#define USE_EMISSIVEMAP" : "", parameters.bumpMap ? "#define USE_BUMPMAP" : "", + parameters.reflectivityMap ? "#define USE_REFLECTIVITYMAP" : "", + parameters.roughnessMap ? "#define USE_ROUGHNESSMAP" : "", + parameters.metallicMap ? "#define USE_METALLICMAP" : "", parameters.normalMap ? "#define USE_NORMALMAP" : "", parameters.specularMap ? "#define USE_SPECULARMAP" : "", parameters.vertexColors ? "#define USE_COLOR" : "", + parameters.clearCoat ? "#define CLEARCOAT" : "", + + parameters.translucency ? "#define TRANSLUCENCY" : "", + + parameters.anisotropy ? "#define ANISOTROPY" : "", + parameters.anisotropyMap ? "#define USE_ANISOTROPYMAP" : "", + ( parameters.anisotropy && parameters.anisotropyRotation ) ? "#define ANISOTROPYROTATION" : "", + ( parameters.anisotropy && parameters.anisotropyRotationMap ) ? "#define USE_ANISOTROPYROTATIONMAP" : "", + + parameters.falloff ? "#define FALLOFF" : "", - parameters.metal ? "#define METAL" : "", parameters.wrapAround ? "#define WRAP_AROUND" : "", parameters.doubleSided ? "#define DOUBLE_SIDED" : "", parameters.flipSided ? "#define FLIP_SIDED" : "", @@ -28657,17 +30871,19 @@ THREE.WebGLRenderer = function ( parameters ) { parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", + supportsShaderTextureLOD ? "#define TEXTURE_CUBE_LOD_EXT" : "", + "uniform mat4 viewMatrix;", "uniform vec3 cameraPosition;", "" ].join("\n"); - var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader ); - var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader ); + var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader, shaderID, simpleCode ); + var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader, shaderID, simpleCode ); - _gl.attachShader( program, glVertexShader ); - _gl.attachShader( program, glFragmentShader ); + _gl.attachShader( program, glVertexShader, code ); + _gl.attachShader( program, glFragmentShader, code ); // Force a particular attribute to index 0. // because potentially expensive emulation is done by browser if attribute 0 is disabled. @@ -28680,18 +30896,29 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.linkProgram( program ); - if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) { - - console.error( 'Could not initialise shader' ); - console.error( 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) ); - console.error( 'gl.getError()', _gl.getError() ); + var programLogInfo = _gl.getProgramInfoLog( program ); - } - - if ( _gl.getProgramInfoLog( program ) !== '' ) { - - console.error( 'gl.getProgramInfoLog()', _gl.getProgramInfoLog( program ) ); + if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) { + var gl_error_message = _gl.getError(); + THREE.onerror( shaderID + ' shader program error: ' + gl_error_message + '\n ' + programLogInfo, { + shaderID: shaderID, + programInfo: programLogInfo, + glError: gl_error_message, + vertexShader: prefix_vertex + vertexShader, + fragmentShader: prefix_fragment + fragmentShader, + getProgramParameter_LINK_STATUS: _gl.getProgramParameter( program, _gl.LINK_STATUS ), + getProgramParameter_VALIDATE_STATUS: _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ), + getProgramParameter_ATTACHED_SHADERS: _gl.getProgramParameter( program, _gl.ATTACHED_SHADERS ), + getProgramParameter_ACTIVE_ATTRIBUTES: _gl.getProgramParameter( program, _gl.ACTIVE_ATTRIBUTES ), + getProgramParameter_ACTIVE_UNIFORMS: _gl.getProgramParameter( program, _gl.ACTIVE_UNIFORMS ), + gl_MAX_VARYING_VECTORS: _gl.getParameter(_gl.MAX_VARYING_VECTORS), + gl_MAX_VERTEX_ATTRIBS: _gl.getParameter(_gl.MAX_VERTEX_ATTRIBS), + gl_MAX_VERTEX_UNIFORM_VECTORS: _gl.getParameter(_gl.MAX_VERTEX_UNIFORM_VECTORS), + gl_MAX_VERTEX_TEXTURE_IMAGE_UNITS: _gl.getParameter(_gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS), + gl_MAX_FRAGMENT_UNIFORM_VECTORS: _gl.getParameter(_gl.MAX_FRAGMENT_UNIFORM_VECTORS), + gl_MAX_TEXTURE_IMAGE_UNITS: _gl.getParameter(_gl.MAX_TEXTURE_IMAGE_UNITS) + } ); } // clean up @@ -28699,9 +30926,6 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.deleteShader( glFragmentShader ); _gl.deleteShader( glVertexShader ); - // console.log( prefix_fragment + fragmentShader ); - // console.log( prefix_vertex + vertexShader ); - program.uniforms = {}; program.attributes = {}; @@ -28820,7 +31044,7 @@ THREE.WebGLRenderer = function ( parameters ) { }; - function getShader ( type, string ) { + function getShader ( type, string, shaderID, simpleCode ) { var shader; @@ -28839,8 +31063,20 @@ THREE.WebGLRenderer = function ( parameters ) { if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) { - console.error( _gl.getShaderInfoLog( shader ) ); - console.error( addLineNumbers( string ) ); + THREE.onerror( "shader error: " + shaderID + "." + type, { + getShaderParameter: _gl.getShaderParameter( shader, _gl.COMPILE_STATUS ), + shaderInfoLog: _gl.getShaderInfoLog( shader ), + shaderCode: addLineNumbers( string ), + getError: _gl.getError(), + simpleCode: simpleCode, + gl_MAX_VARYING_VECTORS: _gl.getParameter(_gl.MAX_VARYING_VECTORS), + gl_MAX_VERTEX_ATTRIBS: _gl.getParameter(_gl.MAX_VERTEX_ATTRIBS), + gl_MAX_VERTEX_UNIFORM_VECTORS: _gl.getParameter(_gl.MAX_VERTEX_UNIFORM_VECTORS), + gl_MAX_VERTEX_TEXTURE_IMAGE_UNITS: _gl.getParameter(_gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS), + gl_MAX_FRAGMENT_UNIFORM_VECTORS: _gl.getParameter(_gl.MAX_FRAGMENT_UNIFORM_VECTORS), + gl_MAX_TEXTURE_IMAGE_UNITS: _gl.getParameter(_gl.MAX_TEXTURE_IMAGE_UNITS) + } ); + return null; } @@ -28884,7 +31120,40 @@ THREE.WebGLRenderer = function ( parameters ) { }; - this.setTexture = function ( texture, slot ) { + var _reportIfError = function ( description, optionalData ) { + var errorCode = _gl.getError(); + if( errorCode === _gl.NO_ERROR ) { + return; + } + var errorMessage = ""; + if( errorCode === _gl.OUT_OF_MEMORY ) { + errorMessage = "OUT_OF_MEMORY"; + } + else if( errorCode === _gl.INVALID_ENUM ) { + errorMessage = "INVALID_ENUM"; + } + else if( errorCode === _gl.INVALID_OPERATION ) { + errorMessage = "INVALID_OPERATION"; + } + else if( errorCode === _gl.INVALID_VALUE ) { + errorMessage = "INVALID_VALUE"; + } + else if( errorCode === _gl.INVALID_FRAMEBUFFER_OPERATION ) { + errorMessage = "INVALID_FRAMEBUFFER_OPERATION"; + } + else if( errorCode === _gl.CONTEXT_LOST_WEBGL ) { + errorMessage = "CONTEXT_LOST_WEBGL"; + } + else if( errorCode === _gl.NO_ERROR ) { + errorMessage = "NO_ERROR"; + } + else { + errorMessage = "Unknown code: " + errorCode; + } + THREE.onerror( "WebGL Error: " + errorMessage + " (" + description + ")", optionalData ); + }; + + this.setTexture = function ( texture, slot ) { if ( texture.needsUpdate ) { @@ -28928,7 +31197,7 @@ THREE.WebGLRenderer = function ( parameters ) { mipmap = mipmaps[ i ]; _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - + _reportIfError( "_gl.texImage2D DataTexture Mipmaps, texture.name: " + texture.name, texture ); } texture.generateMipmaps = false; @@ -28936,7 +31205,7 @@ THREE.WebGLRenderer = function ( parameters ) { } else { _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); - + _reportIfError( "_gl.texImage2D DataTexture, texture.name: " + texture.name, texture ); } } else if ( texture instanceof THREE.CompressedTexture ) { @@ -28946,8 +31215,10 @@ THREE.WebGLRenderer = function ( parameters ) { mipmap = mipmaps[ i ]; if ( texture.format!==THREE.RGBAFormat ) { _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + _reportIfError( "_gl.texImage2D CompressedTexture Non RGBA, texture.name: " + texture.name, texture ); } else { _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + _reportIfError( "_gl.texImage2D CompressedTexture, texture.name: " + texture.name, texture ); } } @@ -28964,7 +31235,8 @@ THREE.WebGLRenderer = function ( parameters ) { mipmap = mipmaps[ i ]; _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); - + _reportIfError( "_gl.texImage2D Mipmaps, texture.name: " + texture.name, texture ); + } texture.generateMipmaps = false; @@ -28972,12 +31244,17 @@ THREE.WebGLRenderer = function ( parameters ) { } else { _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image ); + _reportIfError( "_gl.texImage2D, texture.name: " + texture.name, texture ); } } - if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); + if ( texture.generateMipmaps && isImagePowerOfTwo ) { + _gl.generateMipmap( _gl.TEXTURE_2D ); + _reportIfError( "_gl.generateMipmap, texture.name: " + texture.name, texture ); + } + texture.needsUpdate = false; @@ -29069,9 +31346,10 @@ THREE.WebGLRenderer = function ( parameters ) { if( !isCompressed ) { _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); - + _reportIfError( "_gl.texImage2D CubeMap, texture.name: " + texture.name, { texture: texture, cubeImage: cubeImage, index: i } ); + } else { - + var mipmap, mipmaps = cubeImage[ i ].mipmaps; for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { @@ -29080,9 +31358,11 @@ THREE.WebGLRenderer = function ( parameters ) { if ( texture.format!==THREE.RGBAFormat ) { _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - + _reportIfError( "_gl.compressedTexImage2D CubeMap Mipmaps Compressed, texture.name: " + texture.name, texture ); + } else { _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + _reportIfError( "_gl.texImage2D CubeMap Mipmaps Compressed RGBA, texture.name: " + texture.name, texture ); } } @@ -29092,7 +31372,8 @@ THREE.WebGLRenderer = function ( parameters ) { if ( texture.generateMipmaps && isImagePowerOfTwo ) { _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - + _reportIfError( "_gl.generateMipmap CubeMap Mipmaps, texture.name: " + texture.name, texture ); + } texture.needsUpdate = false; @@ -29130,11 +31411,15 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); + var optionsString = ""; + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + optionsString = "renderTarget: " + renderTarget.width + "+" + renderTarget.height + " DEPTH_ATTACHMENT"; + /* For some reason this is not working. Defaulting to RGBA4. } else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) { @@ -29146,12 +31431,21 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + optionsString = "renderTarget: " + renderTarget.width + "+" + renderTarget.height + " DEPTH_STENCIL_ATTACHMENT"; + } else { _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); + optionsString = "renderTarget: " + renderTarget.width + "+" + renderTarget.height + " RGBA4"; + } + if (_gl.checkFramebufferStatus(_gl.FRAMEBUFFER) != _gl.FRAMEBUFFER_COMPLETE) { + console.log( renderTarget ); + throw new Error('(A) Rendering to this texture (renderTarget.name: ' + renderTarget.name + ') is not supported (incomplete framebuffer) ' + optionsString ); + } + }; this.setRenderTarget = function ( renderTarget ) { @@ -29189,13 +31483,17 @@ THREE.WebGLRenderer = function ( parameters ) { renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer(); _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + _reportIfError( "_gl.texImage2D CubeMap, renderTarget.name: " + renderTarget.name, renderTarget ); setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget ); } - if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + if ( isTargetPowerOfTwo ) { + _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + _reportIfError( "_gl.generateMipmap, CubeMap, renderTarget.name: " + renderTarget.name, renderTarget ); + } } else { @@ -29215,19 +31513,30 @@ THREE.WebGLRenderer = function ( parameters ) { setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo ); _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + _reportIfError( "_gl.texImage2D, renderTarget.name: " + renderTarget.name, renderTarget ); setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D ); if ( renderTarget.shareDepthFrom ) { + var optionsString = "glFormat: " + glFormat + " glType: " + glType; + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); + optionsString = " renderTarget: " + renderTarget.width + "+" + renderTarget.height + " DEPTH_ATTACHMENT"; + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); + optionsString = " renderTarget: " + renderTarget.width + "+" + renderTarget.height + " DEPTH_STENCIL_ATTACHMENT"; + + } + + if (_gl.checkFramebufferStatus(_gl.FRAMEBUFFER) != _gl.FRAMEBUFFER_COMPLETE) { + throw new Error('(B) Rendering to this texture (renderTarget.name: ' + renderTarget.name + ') is not supported (incomplete framebuffer) ' + optionsString ); } } else { @@ -29236,7 +31545,11 @@ THREE.WebGLRenderer = function ( parameters ) { } - if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); + if ( isTargetPowerOfTwo ) { + _gl.generateMipmap( _gl.TEXTURE_2D ); + _reportIfError( "_gl.generateMipmap, renderTarget.name: " + renderTarget.name, renderTarget ); + } + } @@ -29309,12 +31622,14 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + _reportIfError( "_gl.generateMipmap CubeMap, renderTarget.name: " + renderTarget.name, renderTarget ); _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); } else { _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); _gl.generateMipmap( _gl.TEXTURE_2D ); + _reportIfError( "_gl.generateMipmap, renderTarget.name: " + renderTarget.name, renderTarget ); _gl.bindTexture( _gl.TEXTURE_2D, null ); } @@ -29362,6 +31677,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( p === THREE.IntType ) return _gl.INT; if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; if ( p === THREE.FloatType ) return _gl.FLOAT; + if ( p === THREE.HalfType ) return 0x8D61; if ( p === THREE.AlphaFormat ) return _gl.ALPHA; if ( p === THREE.RGBFormat ) return _gl.RGB; @@ -29428,7 +31744,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( maxBones < object.bones.length ) { - console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" ); + THREE.onwarning( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" ); } @@ -29446,6 +31762,7 @@ THREE.WebGLRenderer = function ( parameters ) { var pointLights = 0; var spotLights = 0; var hemiLights = 0; + var areaLights = 0; for ( var l = 0, ll = lights.length; l < ll; l ++ ) { @@ -29457,10 +31774,11 @@ THREE.WebGLRenderer = function ( parameters ) { if ( light instanceof THREE.PointLight ) pointLights ++; if ( light instanceof THREE.SpotLight ) spotLights ++; if ( light instanceof THREE.HemisphereLight ) hemiLights ++; + if ( light instanceof THREE.AreaLight ) areaLights ++; } - return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights }; + return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights, 'area': areaLights }; }; @@ -29501,19 +31819,20 @@ THREE.WebGLRenderer = function ( parameters ) { if ( _gl === null ) { - throw 'Error creating WebGL context.'; + THREE.onerror( 'Error creating WebGL context.' ); } } catch ( error ) { - console.error( error ); + THREE.onerror( error ); } _glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' ); _glExtensionTextureFloatLinear = _gl.getExtension( 'OES_texture_float_linear' ); _glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' ); + _glExtensionShaderTextureLOD = _gl.getExtension( 'EXT_shader_texture_lod' ); _glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); @@ -29531,6 +31850,12 @@ THREE.WebGLRenderer = function ( parameters ) { } + if ( ! _glExtensionShaderTextureLOD ) { + + console.log( 'THREE.WebGLRenderer: Shader texture LOD not supported.' ); + + } + if ( ! _glExtensionTextureFilterAnisotropic ) { console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' ); @@ -29576,7 +31901,7 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA ); _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); - + _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); }; @@ -29590,13 +31915,15 @@ THREE.WebGLRenderer = function ( parameters ) { this.addPostPlugin( new THREE.LensFlarePlugin() ); }; + /** * @author szimek / https://github.com/szimek/ * @author alteredq / http://alteredqualia.com/ */ -THREE.WebGLRenderTarget = function ( width, height, options ) { +THREE.WebGLRenderTarget = function ( width, height, options, name ) { + this.name = name || ""; this.width = width; this.height = height; @@ -29619,7 +31946,7 @@ THREE.WebGLRenderTarget = function ( width, height, options ) { this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; - this.generateMipmaps = true; + this.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; this.shareDepthFrom = null; @@ -29631,7 +31958,7 @@ THREE.WebGLRenderTarget.prototype = { clone: function () { - var tmp = new THREE.WebGLRenderTarget( this.width, this.height ); + var tmp = new THREE.WebGLRenderTarget( this.width, this.height, null, this.name + " Clone" ); tmp.wrapS = this.wrapS; tmp.wrapT = this.wrapT; @@ -29667,6 +31994,7 @@ THREE.WebGLRenderTarget.prototype = { }; THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype ); + /** * @author alteredq / http://alteredqualia.com */ @@ -29680,6 +32008,7 @@ THREE.WebGLRenderTargetCube = function ( width, height, options ) { }; THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype ); + /** * @author mrdoob / http://mrdoob.com/ */ @@ -29700,6 +32029,7 @@ THREE.RenderableVertex.prototype.copy = function ( vertex ) { this.positionScreen.copy( vertex.positionScreen ); }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -29726,6 +32056,7 @@ THREE.RenderableFace = function () { this.z = 0; }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -29738,6 +32069,7 @@ THREE.RenderableObject = function () { this.z = 0; }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -29758,6 +32090,7 @@ THREE.RenderableSprite = function () { this.material = null; }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -29775,6 +32108,7 @@ THREE.RenderableLine = function () { this.z = 0; }; + /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ @@ -30132,6 +32466,7 @@ THREE.GeometryUtils = { } }; + /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ @@ -30552,14 +32887,14 @@ THREE.ImageUtils = { if ( header[ off_magic ] !== DDS_MAGIC ) { - console.error( "ImageUtils.parseDDS(): Invalid magic number in DDS header" ); + THREE.onerror( "ImageUtils.parseDDS(): Invalid magic number in DDS header" ); return dds; } if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) { - console.error( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" ); + THREE.onerror( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" ); return dds; } @@ -30601,7 +32936,7 @@ THREE.ImageUtils = { blockBytes = 64; dds.format = THREE.RGBAFormat; } else { - console.error( "ImageUtils.parseDDS(): Unsupported FourCC code: ", int32ToFourCC( fourCC ) ); + THREE.onerror( "ImageUtils.parseDDS(): Unsupported FourCC code: ", int32ToFourCC( fourCC ) ); return dds; } } @@ -30789,6 +33124,7 @@ THREE.ImageUtils = { } }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -30829,6 +33165,7 @@ THREE.SceneUtils = { } }; + /** * @author zz85 / http://www.lab4games.net/zz85/blog * @author alteredq / http://alteredqualia.com/ @@ -31153,10 +33490,8 @@ THREE.FontUtils.generateShapes = function( text, parameters ) { //** Triangulate: ERROR - probable bad polygon! - //throw ( "Warning, unable to triangulate polygon!" ); - //return null; // Sometimes warning is fine, especially polygons are triangulated in reverse. - console.log( "Warning, unable to triangulate polygon!" ); + THREE.onwarning( "Warning, unable to triangulate polygon!" ); if ( indices ) return vertIndices; return result; @@ -31291,6 +33626,7 @@ THREE.FontUtils.generateShapes = function( text, parameters ) { // To use the typeface.js face files, hook up the API self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace }; THREE.typeface_js = self._typeface_js; + /** * @author zz85 / http://www.lab4games.net/zz85/blog * Extensible curve object @@ -31336,7 +33672,7 @@ THREE.Curve = function () { THREE.Curve.prototype.getPoint = function ( t ) { - console.log( "Warning, getPoint() not implemented!" ); + THREE.onwarning( "Warning, getPoint() not implemented!" ); return null; }; @@ -31626,6 +33962,7 @@ THREE.Curve.create = function ( constructor, getPointFunc ) { return constructor; }; + /** * @author zz85 / http://www.lab4games.net/zz85/blog * @@ -31952,6 +34289,7 @@ THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) { }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -32012,6 +34350,7 @@ THREE.Gyroscope.prototype.quaternionObject = new THREE.Quaternion(); THREE.Gyroscope.prototype.scaleWorld = new THREE.Vector3(); THREE.Gyroscope.prototype.scaleObject = new THREE.Vector3(); + /** * @author zz85 / http://www.lab4games.net/zz85/blog * Creates free form 2d path using series of points, lines or curves. @@ -32641,6 +34980,7 @@ THREE.Path.prototype.toShapes = function( isCCW ) { return shapes; }; + /** * @author zz85 / http://www.lab4games.net/zz85/blog * Defines a 2d shape plane using paths. @@ -33214,6 +35554,7 @@ THREE.Shape.Utils = { }; + /************************************************************** * Line **************************************************************/ @@ -33250,7 +35591,8 @@ THREE.LineCurve.prototype.getTangent = function( t ) { return tangent.normalize(); -};/************************************************************** +}; +/************************************************************** * Quadratic Bezier curve **************************************************************/ @@ -33292,7 +35634,8 @@ THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) { return tangent; -};/************************************************************** +}; +/************************************************************** * Cubic Bezier curve **************************************************************/ @@ -33330,7 +35673,8 @@ THREE.CubicBezierCurve.prototype.getTangent = function( t ) { return tangent; -};/************************************************************** +}; +/************************************************************** * Spline curve **************************************************************/ @@ -33362,7 +35706,8 @@ THREE.SplineCurve.prototype.getPoint = function ( t ) { return v; -};/************************************************************** +}; +/************************************************************** * Ellipse curve **************************************************************/ @@ -33407,6 +35752,7 @@ THREE.EllipseCurve.prototype.getPoint = function ( t ) { return new THREE.Vector2( tx, ty ); }; + /************************************************************** * Arc curve **************************************************************/ @@ -33416,7 +35762,8 @@ THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); }; -THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype );/************************************************************** +THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype ); +/************************************************************** * Line3D **************************************************************/ @@ -33443,6 +35790,7 @@ THREE.LineCurve3 = THREE.Curve.create( } ); + /************************************************************** * Quadratic Bezier 3D curve **************************************************************/ @@ -33469,7 +35817,8 @@ THREE.QuadraticBezierCurve3 = THREE.Curve.create( } -);/************************************************************** +); +/************************************************************** * Cubic Bezier 3D curve **************************************************************/ @@ -33496,7 +35845,8 @@ THREE.CubicBezierCurve3 = THREE.Curve.create( } -);/************************************************************** +); +/************************************************************** * Spline 3D curve **************************************************************/ @@ -33540,33 +35890,33 @@ THREE.SplineCurve3 = THREE.Curve.create( ); -/* THREE.SplineCurve3.prototype.getTangent = function(t) { - var v = new THREE.Vector3(); - var c = []; - var points = this.points, point, intPoint, weight; - point = ( points.length - 1 ) * t; +// THREE.SplineCurve3.prototype.getTangent = function(t) { +// var v = new THREE.Vector3(); +// var c = []; +// var points = this.points, point, intPoint, weight; +// point = ( points.length - 1 ) * t; - intPoint = Math.floor( point ); - weight = point - intPoint; +// intPoint = Math.floor( point ); +// weight = point - intPoint; - c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; - c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; +// c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; +// c[ 1 ] = intPoint; +// c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; +// c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; - var pt0 = points[ c[0] ], - pt1 = points[ c[1] ], - pt2 = points[ c[2] ], - pt3 = points[ c[3] ]; +// var pt0 = points[ c[0] ], +// pt1 = points[ c[1] ], +// pt2 = points[ c[2] ], +// pt3 = points[ c[3] ]; - // t = weight; - v.x = THREE.Curve.Utils.tangentSpline( t, pt0.x, pt1.x, pt2.x, pt3.x ); - v.y = THREE.Curve.Utils.tangentSpline( t, pt0.y, pt1.y, pt2.y, pt3.y ); - v.z = THREE.Curve.Utils.tangentSpline( t, pt0.z, pt1.z, pt2.z, pt3.z ); - return v; +// // t = weight; +// v.x = THREE.Curve.Utils.tangentSpline( t, pt0.x, pt1.x, pt2.x, pt3.x ); +// v.y = THREE.Curve.Utils.tangentSpline( t, pt0.y, pt1.y, pt2.y, pt3.y ); +// v.z = THREE.Curve.Utils.tangentSpline( t, pt0.z, pt1.z, pt2.z, pt3.z ); -}*/ +// return v; +// } /************************************************************** * Closed Spline 3D curve **************************************************************/ @@ -33605,7 +35955,8 @@ THREE.ClosedSplineCurve3 = THREE.Curve.create( } -);/** +); +/** * @author mikael emtinger / http://gomo.se/ */ @@ -33653,7 +36004,7 @@ THREE.AnimationHandler = (function() { that.add = function( data ) { if ( library[ data.name ] !== undefined ) - console.log( "THREE.AnimationHandler.add: Warning! " + data.name + " already exists in library. Overwriting." ); + THREE.onwarning( "THREE.AnimationHandler.add: Warning! " + data.name + " already exists in library. Overwriting." ); library[ data.name ] = data; initData( data ); @@ -33673,7 +36024,7 @@ THREE.AnimationHandler = (function() { } else { - console.log( "THREE.AnimationHandler.get: Couldn't find animation " + name ); + THREE.onwarning( "THREE.AnimationHandler.get: Couldn't find animation " + name ); return null; } @@ -33851,6 +36202,7 @@ THREE.AnimationHandler = (function() { return that; }()); + /** * @author mikael emtinger / http://gomo.se/ * @author mrdoob / http://mrdoob.com/ @@ -34200,6 +36552,7 @@ THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) { return this.data.hierarchy[ h ].keys[ keys.length - 1 ]; }; + /** * @author mikael emtinger / http://gomo.se/ * @author mrdoob / http://mrdoob.com/ @@ -34476,6 +36829,7 @@ THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) { return keys[ keys.length - 1 ]; }; + /** * @author mrdoob / http://mrdoob.com */ @@ -34546,6 +36900,7 @@ THREE.MorphAnimation.prototype = { } )() }; + /** * Camera for rendering cube maps * - renders scene into axis-aligned cube @@ -34556,6 +36911,7 @@ THREE.MorphAnimation.prototype = { THREE.CubeCamera = function ( near, far, cubeResolution ) { THREE.Object3D.call( this ); + this.className = "CubeCamera"; var fov = 90, aspect = 1; @@ -34623,6 +36979,7 @@ THREE.CubeCamera = function ( near, far, cubeResolution ) { }; THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); + /** * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog * @@ -34637,6 +36994,7 @@ THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); THREE.CombinedCamera = function ( width, height, fov, near, far, orthoNear, orthoFar ) { THREE.Camera.call( this ); + this.className = "CombinedCamera"; this.fov = fov; @@ -34859,6 +37217,7 @@ THREE.CombinedCamera.prototype.toBottomView = function() { this.rotationAutoUpdate = false; }; + /** * @author mrdoob / http://mrdoob.com/ * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as @@ -34867,6 +37226,7 @@ THREE.CombinedCamera.prototype.toBottomView = function() { THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { THREE.Geometry.call( this ); + this.className = "BoxGeometry"; var scope = this; @@ -34979,6 +37339,7 @@ THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegmen }; THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype ); + /** * @author hughes */ @@ -34986,6 +37347,7 @@ THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { THREE.Geometry.call( this ); + this.className = "CircleGeometry"; this.radius = radius = radius || 50; this.segments = segments = segments !== undefined ? Math.max( 3, segments ) : 8; @@ -35033,9 +37395,11 @@ THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { }; THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype ); + // DEPRECATED THREE.CubeGeometry = THREE.BoxGeometry; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -35043,6 +37407,7 @@ THREE.CubeGeometry = THREE.BoxGeometry; THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded ) { THREE.Geometry.call( this ); + this.className = "CylinderGeometry"; this.radiusTop = radiusTop = radiusTop !== undefined ? radiusTop : 20; this.radiusBottom = radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; @@ -35193,6 +37558,7 @@ THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegme } THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype ); + /** * @author zz85 / http://www.lab4games.net/zz85/blog * @@ -35227,6 +37593,7 @@ THREE.ExtrudeGeometry = function ( shapes, options ) { } THREE.Geometry.call( this ); + this.className = "ExtrudeGeometry"; shapes = shapes instanceof Array ? shapes : [ shapes ]; @@ -35374,7 +37741,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { function scalePt2 ( pt, vec, size ) { - if ( !vec ) console.log( "die" ); + if ( !vec ) return THREE.onerror( "die, vec not specified" ); return vec.clone().multiplyScalar( size ).add( pt ); @@ -35901,6 +38268,7 @@ THREE.ExtrudeGeometry.__v3 = new THREE.Vector2(); THREE.ExtrudeGeometry.__v4 = new THREE.Vector2(); THREE.ExtrudeGeometry.__v5 = new THREE.Vector2(); THREE.ExtrudeGeometry.__v6 = new THREE.Vector2(); + /** * @author jonobr1 / http://jonobr1.com * @@ -35920,6 +38288,7 @@ THREE.ExtrudeGeometry.__v6 = new THREE.Vector2(); THREE.ShapeGeometry = function ( shapes, options ) { THREE.Geometry.call( this ); + this.className = "ShapeGeometry"; if ( shapes instanceof Array === false ) shapes = [ shapes ]; @@ -36037,6 +38406,7 @@ THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { } }; + /** * @author astrodud / http://astrodud.isgreat.org/ * @author zz85 / https://github.com/zz85 @@ -36052,6 +38422,7 @@ THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) { THREE.Geometry.call( this ); + this.className = "LatheGeometry"; segments = segments || 12; phiStart = phiStart || 0; @@ -36133,6 +38504,7 @@ THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) { }; THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); + /** * @author mrdoob / http://mrdoob.com/ * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as @@ -36141,6 +38513,7 @@ THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) { THREE.Geometry.call( this ); + this.className = "PlaneGeometry"; this.width = width; this.height = height; @@ -36213,6 +38586,7 @@ THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) }; THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype ); + /** * @author Kaleb Murphy */ @@ -36220,6 +38594,7 @@ THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { THREE.Geometry.call( this ); + this.className = "RingGeometry"; innerRadius = innerRadius || 0; outerRadius = outerRadius || 50; @@ -36285,6 +38660,7 @@ THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegm }; THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype ); + /** * @author mrdoob / http://mrdoob.com/ */ @@ -36292,6 +38668,7 @@ THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { THREE.Geometry.call( this ); + this.className = "SphereGeometry"; this.radius = radius = radius || 50; @@ -36386,6 +38763,7 @@ THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStar }; THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); + /** * @author zz85 / http://www.lab4games.net/zz85/blog * @author alteredq / http://alteredqualia.com/ @@ -36425,6 +38803,7 @@ THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.TextGeometry = function ( text, parameters ) { + this.className = "TextGeometry"; parameters = parameters || {}; @@ -36445,6 +38824,7 @@ THREE.TextGeometry = function ( text, parameters ) { }; THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype ); + /** * @author oosmoxiecode * @author mrdoob / http://mrdoob.com/ @@ -36454,7 +38834,8 @@ THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype ); THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) { THREE.Geometry.call( this ); - + this.className = "TorusGeometry"; + var scope = this; this.radius = radius || 100; @@ -36517,6 +38898,7 @@ THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, }; THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); + /** * @author oosmoxiecode * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473 @@ -36525,6 +38907,7 @@ THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) { THREE.Geometry.call( this ); + this.className = "TorusKnotGeometry"; var scope = this; @@ -36620,6 +39003,7 @@ THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegmen }; THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); + /** * @author WestLangley / https://github.com/WestLangley * @author zz85 / https://github.com/zz85 @@ -36636,6 +39020,7 @@ THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.TubeGeometry = function( path, segments, radius, radialSegments, closed ) { THREE.Geometry.call( this ); + this.className = "TubeGeometry"; this.path = path; this.segments = segments || 64; @@ -36893,6 +39278,7 @@ THREE.TubeGeometry.FrenetFrames = function(path, segments, closed) { } }; + /** * @author clockworkgeek / https://github.com/clockworkgeek * @author timothypratley / https://github.com/timothypratley @@ -36902,6 +39288,7 @@ THREE.TubeGeometry.FrenetFrames = function(path, segments, closed) { THREE.PolyhedronGeometry = function ( vertices, faces, radius, detail ) { THREE.Geometry.call( this ); + this.className = "PolyhedronGeometry"; radius = radius || 1; detail = detail || 0; @@ -37117,6 +39504,7 @@ THREE.PolyhedronGeometry = function ( vertices, faces, radius, detail ) { }; THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + /** * @author timothypratley / https://github.com/timothypratley */ @@ -37142,10 +39530,12 @@ THREE.IcosahedronGeometry = function ( radius, detail ) { ]; THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); + this.className = "IcosahedronGeometry"; }; THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + /** * @author timothypratley / https://github.com/timothypratley */ @@ -37161,14 +39551,18 @@ THREE.OctahedronGeometry = function ( radius, detail ) { ]; THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); + this.className = "OctahedronGeometry"; + }; THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + /** * @author timothypratley / https://github.com/timothypratley */ THREE.TetrahedronGeometry = function ( radius, detail ) { + this.className = "TetrahedronGeometry"; var vertices = [ [ 1, 1, 1 ], [ -1, -1, 1 ], [ -1, 1, -1 ], [ 1, -1, -1 ] @@ -37183,6 +39577,7 @@ THREE.TetrahedronGeometry = function ( radius, detail ) { }; THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + /** * @author zz85 / https://github.com/zz85 * Parametric Surfaces Geometry @@ -37195,6 +39590,7 @@ THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.ParametricGeometry = function ( func, slices, stacks ) { THREE.Geometry.call( this ); + this.className = "ParametricGeometry"; var verts = this.vertices; var faces = this.faces; @@ -37260,6 +39656,7 @@ THREE.ParametricGeometry = function ( func, slices, stacks ) { }; THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype ); + /** * @author sroucheray / http://sroucheray.org/ * @author mrdoob / http://mrdoob.com/ @@ -37286,10 +39683,12 @@ THREE.AxisHelper = function ( size ) { var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); THREE.Line.call( this, geometry, material, THREE.LinePieces ); + this.className = "AxisHelper"; }; THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype ); + /** * @author WestLangley / http://github.com/WestLangley * @author zz85 / http://github.com/zz85 @@ -37311,6 +39710,7 @@ THREE.ArrowHelper = function ( dir, origin, length, hex, headLength, headWidth ) // dir is assumed to be normalized THREE.Object3D.call( this ); + this.className = "ArrowHelper"; if ( hex === undefined ) hex = 0xffff00; if ( length === undefined ) length = 1; @@ -37392,6 +39792,7 @@ THREE.ArrowHelper.prototype.setColor = function ( hex ) { this.cone.material.color.setHex( hex ); }; + /** * @author mrdoob / http://mrdoob.com/ */ @@ -37479,6 +39880,7 @@ THREE.BoxHelper.prototype.update = function ( object ) { this.matrixWorld = object.matrixWorld; }; + /** * @author WestLangley / http://github.com/WestLangley */ @@ -37508,6 +39910,7 @@ THREE.BoundingBoxHelper.prototype.update = function () { this.box.center( this.position ); }; + /** * @author alteredq / http://alteredqualia.com/ * @@ -37693,6 +40096,7 @@ THREE.CameraHelper.prototype.update = function () { }; }(); + /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ @@ -37764,6 +40168,7 @@ THREE.DirectionalLightHelper.prototype.update = function () { }(); + /** * @author WestLangley / http://github.com/WestLangley */ @@ -37848,6 +40253,7 @@ THREE.EdgesHelper = function ( object, hex ) { }; THREE.EdgesHelper.prototype = Object.create( THREE.Line.prototype ); + /** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley @@ -37924,6 +40330,7 @@ THREE.FaceNormalsHelper.prototype.update = ( function ( object ) { }()); + /** * @author mrdoob / http://mrdoob.com/ */ @@ -37963,6 +40370,7 @@ THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) { this.geometry.colorsNeedUpdate = true; } + /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ @@ -38021,6 +40429,7 @@ THREE.HemisphereLightHelper.prototype.update = function () { }(); + /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ @@ -38093,6 +40502,7 @@ THREE.PointLightHelper.prototype.update = function () { }; + /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ @@ -38152,6 +40562,7 @@ THREE.SpotLightHelper.prototype.update = function () { }; }(); + /** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley @@ -38252,6 +40663,7 @@ THREE.VertexNormalsHelper.prototype.update = ( function ( object ) { } }()); + /** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley @@ -38348,6 +40760,7 @@ THREE.VertexTangentsHelper.prototype.update = ( function ( object ) { } }()); + /** * @author mrdoob / http://mrdoob.com/ */ @@ -38514,6 +40927,7 @@ THREE.WireframeHelper = function ( object, hex ) { }; THREE.WireframeHelper.prototype = Object.create( THREE.Line.prototype ); + /** * @author alteredq / http://alteredqualia.com/ */ @@ -38527,6 +40941,7 @@ THREE.ImmediateRenderObject = function () { }; THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype ); + /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ @@ -38616,6 +41031,7 @@ THREE.LensFlare.prototype.updateLensFlares = function () { + /** * @author alteredq / http://alteredqualia.com/ */ @@ -38838,7 +41254,7 @@ THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { } else { - console.warn( "animation[" + name + "] undefined" ); + THREE.onwarning( "animation[" + name + "] undefined" ); } @@ -38923,6 +41339,7 @@ THREE.MorphBlendMesh.prototype.update = function ( delta ) { } }; + /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ @@ -39226,6 +41643,7 @@ THREE.LensFlarePlugin = function () { }; }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -39337,7 +41755,7 @@ THREE.ShadowMapPlugin = function () { light.shadowCascadeArray[ n ] = virtualLight; - console.log( "Created virtualLight", virtualLight ); + //console.log( "Created virtualLight", virtualLight ); } else { @@ -39369,7 +41787,7 @@ THREE.ShadowMapPlugin = function () { if ( ! light.shadowMap ) { - var shadowFilter = THREE.LinearFilter; + var shadowFilter = THREE.NearestFilter; if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) { @@ -39398,7 +41816,7 @@ THREE.ShadowMapPlugin = function () { } else { - console.error( "Unsupported light type for shadow" ); + THREE.onerror( "Unsupported light type for shadow" ); continue; } @@ -39722,6 +42140,7 @@ THREE.ShadowMapPlugin = function () { }; THREE.ShadowMapPlugin.__projector = new THREE.Projector(); + /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ @@ -40082,6 +42501,7 @@ THREE.SpritePlugin = function () { }; }; + /** * @author alteredq / http://alteredqualia.com/ */ @@ -40282,6 +42702,7 @@ THREE.DepthPassPlugin = function () { }; + /** * @author mikael emtinger / http://gomo.se/ */ @@ -40468,6 +42889,7 @@ THREE.ShaderFlares = { }; + // Export the THREE object for **Node.js**, with // backwards-compatibility for the old `require()` API. If we're in // the browser, add `_` as a global object via a string identifier, @@ -41729,8 +44151,6 @@ var latLon2d = function(lat,lon){ return {x: lat+90, y:lon + 180, rad: rad}; }; - - var addInitialData = function(){ if(this.data.length == 0){ return; @@ -41963,6 +44383,35 @@ var createIntroLines = function(){ this.scene.add(this.introLines); }; +var createMouseBehaviors = function(globe){ + var mouseDown = false, + mousePos = 0, + lastTime = Date.now(), + mouseTimeout; + + globe.domElement.onmousedown = function(e){ mouseDown = true; mousePos = e.clientX; lastTime = Date.now();}; + globe.domElement.onmouseup = function(e){ mouseDown = false; globe.resetRotationSpeed()}; + globe.domElement.onmouseleave = function(e){ mouseDown = false; globe.resetRotationSpeed();}; + + var onmousemove = function(e, secondCall){ + var diff = Date.now() - lastTime; + if(mouseDown && diff){ + + globe.setRotationSpeed(((e.clientX-mousePos)/globe.width) / (diff/1000)); + + lastTime = Date.now(); + mousePos = e.clientX; + clearTimeout(mouseTimeout); + if(!secondCall){ + mouseTimeout = setTimeout(function(){onmousemove(e, true)},100); + } + } + }; + + globe.domElement.onmousemove = onmousemove; +} + + /* globe constructor */ function Globe(width, height, opts){ @@ -41991,34 +44440,35 @@ function Globe(width, height, opts){ markerColor: "#ffcc00", pinColor: "#00eeee", satelliteColor: "#ff0000", - blankPercentage: 0, - thinAntarctica: .01, // only show 1% of antartica... you can't really see it on the map anyhow - mapUrl: "resources/equirectangle_projection.png", introLinesAltitude: 1.10, introLinesDuration: 2000, introLinesColor: "#8FD8D8", introLinesCount: 60, scale: 1.0, dayLength: 28000, - pointsPerDegree: 1.1, - pointSize: .6, - pointsVariance: .2, maxPins: 500, maxMarkers: 4, data: [], tiles: [], - viewAngle: 0 + viewAngle: .1, + cameraAngle: Math.PI }; for(var i in defaults){ if(!this[i]){ this[i] = defaults[i]; - if(opts[i]){ + if(opts[i] !== undefined){ this[i] = opts[i]; } } } + if(this.dayLength === 0){ + this.rotationSpeed = 0; + } else { + this.rotationSpeed = 1000 * 1/this.dayLength; + } + this.setScale(this.scale); this.renderer = new THREE.WebGLRenderer( { antialias: true } ); @@ -42035,6 +44485,9 @@ function Globe(width, height, opts){ this.data[i].when = this.introLinesDuration*((180+this.data[i].lng)/360.0) + 500; } + this.defaultRotationSpeed = this.rotationSpeed; + + createMouseBehaviors(this); } @@ -42046,8 +44499,6 @@ Globe.prototype.init = function(cb){ this.camera = new THREE.PerspectiveCamera( 50, this.width / this.height, 1, this.cameraDistance + 300 ); this.camera.position.z = this.cameraDistance; - this.cameraAngle=(Math.PI); - // create the scene this.scene = new THREE.Scene(); @@ -42087,7 +44538,8 @@ Globe.prototype.addPin = function(lat, lon, text){ var opts = { lineColor: this.pinColor, - topColor: this.pinColor + topColor: this.pinColor, + font: this.font } var altitude = 1.2; @@ -42162,7 +44614,8 @@ Globe.prototype.addMarker = function(lat, lon, text, connected){ var marker; var opts = { markerColor: this.markerColor, - lineColor: this.markerColor + lineColor: this.markerColor, + font: this.font }; if(typeof connected == "boolean" && connected){ @@ -42276,6 +44729,14 @@ Globe.prototype.setScale = function(_scale){ } }; +Globe.prototype.setRotationSpeed = function(rotationSpeed){ + this.rotationSpeed = rotationSpeed; +} + +Globe.prototype.resetRotationSpeed = function(){ + this.rotationSpeed = this.defaultRotationSpeed; +} + Globe.prototype.tick = function(){ if(!this.camera){ @@ -42300,7 +44761,7 @@ Globe.prototype.tick = function(){ var renderTime = new Date() - this.lastRenderDate; this.lastRenderDate = new Date(); - var rotateCameraBy = (2 * Math.PI)/(this.dayLength/renderTime); + var rotateCameraBy = this.rotationSpeed * renderTime/1000 * 2 * Math.PI; this.cameraAngle += rotateCameraBy; @@ -42347,8 +44808,8 @@ Globe.prototype.tick = function(){ this.smokeProvider.tick(this.totalRunTime); this.camera.lookAt( this.scene.position ); - this.renderer.render( this.scene, this.camera ); + this.renderer.render( this.scene, this.camera ); } module.exports = Globe; @@ -43517,4 +45978,4 @@ var utils = { module.exports = utils; -},{}]},{},[1]); \ No newline at end of file +},{}]},{},[1]) \ No newline at end of file diff --git a/display/display-data.js b/display/display-data.js new file mode 100644 index 0000000..47537dc --- /dev/null +++ b/display/display-data.js @@ -0,0 +1,18 @@ +var data = [ + {lat:42.35843,lng:-71.05977, label: "Boston"}, + {lat:25.77427,lng:-80.19366, label: "Miami"}, + {lat:37.77493,lng:-122.41942, label: "San Francisco"}, + {lat:-23.5475,lng:-46.63611, label: "Sao Paulo"}, + {lat:-12.04318,lng:-77.02824, label: "Lima"}, + {lat:21.30694,lng:-157.85833, label: "Honolulu"}, + {lat:-31.95224,lng:115.8614, label: "Perth"}, + {lat:-33.86785,lng:151.20732, label: "Sydney"}, + {lat: -42, lng: 174, label: "New Zealand"}, + {lat:22.28552,lng:114.15769, label: "Hong Kong"}, + {lat:19.07283,lng:72.88261, label: "Mumbai"}, + {lat:30.06263,lng:31.24967, label:"Cairo"}, + {lat:-33.92584,lng:18.42322, label:"Cape Town"}, + {lat:52.52437,lng:13.41053, label:"Berlin"}, + {lat:55.95206,lng:-3.19648, label:"Edinburgh"}, + {lat:55.75222,lng:37.61556, label:"Moscow"}, +] diff --git a/display/display.html b/display/display.html new file mode 100644 index 0000000..59ccbc0 --- /dev/null +++ b/display/display.html @@ -0,0 +1,21 @@ + + + + + + +
+ + + + + + + + + + + + + + diff --git a/display/display.js b/display/display.js new file mode 100644 index 0000000..a1ca5c7 --- /dev/null +++ b/display/display.js @@ -0,0 +1,79 @@ +var globe; + +function createGlobe(){ + + globe = new ENCOM.Globe(window.innerWidth, window.innerHeight, { + data: data, // from the display-data.js + tiles: grid.tiles + }); + + // var defaults = { + // font: "Inconsolata", + // baseColor: "#ffcc00", + // markerColor: "#ffcc00", + // pinColor: "#00eeee", + // satelliteColor: "#ff0000", + // introLinesAltitude: 1.10, + // introLinesDuration: 2000, + // introLinesColor: "#8FD8D8", + // introLinesCount: 60, + // scale: 1.0, + // dayLength: 28000, // set to 0 if you don't want it to spin + // maxPins: 500, + // maxMarkers: 4, + // data: [], + // tiles: [], + // viewAngle: .1, // North-South camera angle; between -Math.PI and Math.PI + // cameraAngle: Math.PI // East-West camera angle; between -Math.PI and Math.PI + // }; + + $("#globe").append(globe.domElement); + + function animate(){ + globe.tick(); + requestAnimationFrame(animate); + } + + /* add some satellites in 4 seconds */ + setTimeout(function(){ + var constellation = []; + var alt = parseFloat($("#globe-sa").val()); + var opts = { + coreColor: "#ff0000", + numWaves: 8 + }; + + for(var i = 0; i< 2; i++){ + for(var j = 0; j< 3; j++){ + constellation.push({ + lat: 50 * i - 30 + 15 * Math.random(), + lon: 120 * j - 120 + 30 * i, + altitude: 1.3 + }); + } + } + + globe.addConstellation(constellation, opts); + }, 4000); + + globe.init(animate); + +} + +/* web font stuff*/ +var wf = document.createElement('script'); +wf.src = ('https:' == document.location.protocol ? 'https' : 'http') + + '://ajax.googleapis.com/ajax/libs/webfont/1.4.7/webfont.js'; +wf.type = 'text/javascript'; +wf.async = 'true'; +var s = document.getElementsByTagName('script')[0]; +s.parentNode.insertBefore(wf, s); + +WebFontConfig = { + google: { + families: ['Inconsolata'] + }, + active: function(){ + createGlobe(); /* start the globe after the font is loaded */ + } +}; diff --git a/display/styles.css b/display/styles.css new file mode 100644 index 0000000..9e171f6 --- /dev/null +++ b/display/styles.css @@ -0,0 +1,13 @@ + +/* 775 by 363 */ + +body { + background-color: #000000; +} + +#globe { + margin: 0; + padding: 0; + width: 100%; + height: 100%; +} diff --git a/src/Globe.js b/src/Globe.js index 325dd52..36cb14c 100644 --- a/src/Globe.js +++ b/src/Globe.js @@ -24,8 +24,6 @@ var latLon2d = function(lat,lon){ return {x: lat+90, y:lon + 180, rad: rad}; }; - - var addInitialData = function(){ if(this.data.length == 0){ return; @@ -258,6 +256,35 @@ var createIntroLines = function(){ this.scene.add(this.introLines); }; +var createMouseBehaviors = function(globe){ + var mouseDown = false, + mousePos = 0, + lastTime = Date.now(), + mouseTimeout; + + globe.domElement.onmousedown = function(e){ mouseDown = true; mousePos = e.clientX; lastTime = Date.now();}; + globe.domElement.onmouseup = function(e){ mouseDown = false; globe.resetRotationSpeed()}; + globe.domElement.onmouseleave = function(e){ mouseDown = false; globe.resetRotationSpeed();}; + + var onmousemove = function(e, secondCall){ + var diff = Date.now() - lastTime; + if(mouseDown && diff){ + + globe.setRotationSpeed(((e.clientX-mousePos)/globe.width) / (diff/1000)); + + lastTime = Date.now(); + mousePos = e.clientX; + clearTimeout(mouseTimeout); + if(!secondCall){ + mouseTimeout = setTimeout(function(){onmousemove(e, true)},100); + } + } + }; + + globe.domElement.onmousemove = onmousemove; +} + + /* globe constructor */ function Globe(width, height, opts){ @@ -286,34 +313,35 @@ function Globe(width, height, opts){ markerColor: "#ffcc00", pinColor: "#00eeee", satelliteColor: "#ff0000", - blankPercentage: 0, - thinAntarctica: .01, // only show 1% of antartica... you can't really see it on the map anyhow - mapUrl: "resources/equirectangle_projection.png", introLinesAltitude: 1.10, introLinesDuration: 2000, introLinesColor: "#8FD8D8", introLinesCount: 60, scale: 1.0, dayLength: 28000, - pointsPerDegree: 1.1, - pointSize: .6, - pointsVariance: .2, maxPins: 500, maxMarkers: 4, data: [], tiles: [], - viewAngle: 0 + viewAngle: .1, + cameraAngle: Math.PI }; for(var i in defaults){ if(!this[i]){ this[i] = defaults[i]; - if(opts[i]){ + if(opts[i] !== undefined){ this[i] = opts[i]; } } } + if(this.dayLength === 0){ + this.rotationSpeed = 0; + } else { + this.rotationSpeed = 1000 * 1/this.dayLength; + } + this.setScale(this.scale); this.renderer = new THREE.WebGLRenderer( { antialias: true } ); @@ -330,6 +358,9 @@ function Globe(width, height, opts){ this.data[i].when = this.introLinesDuration*((180+this.data[i].lng)/360.0) + 500; } + this.defaultRotationSpeed = this.rotationSpeed; + + createMouseBehaviors(this); } @@ -341,8 +372,6 @@ Globe.prototype.init = function(cb){ this.camera = new THREE.PerspectiveCamera( 50, this.width / this.height, 1, this.cameraDistance + 300 ); this.camera.position.z = this.cameraDistance; - this.cameraAngle=(Math.PI); - // create the scene this.scene = new THREE.Scene(); @@ -573,6 +602,14 @@ Globe.prototype.setScale = function(_scale){ } }; +Globe.prototype.setRotationSpeed = function(rotationSpeed){ + this.rotationSpeed = rotationSpeed; +} + +Globe.prototype.resetRotationSpeed = function(){ + this.rotationSpeed = this.defaultRotationSpeed; +} + Globe.prototype.tick = function(){ if(!this.camera){ @@ -597,7 +634,7 @@ Globe.prototype.tick = function(){ var renderTime = new Date() - this.lastRenderDate; this.lastRenderDate = new Date(); - var rotateCameraBy = (2 * Math.PI)/(this.dayLength/renderTime); + var rotateCameraBy = this.rotationSpeed * renderTime/1000 * 2 * Math.PI; this.cameraAngle += rotateCameraBy; @@ -644,8 +681,8 @@ Globe.prototype.tick = function(){ this.smokeProvider.tick(this.totalRunTime); this.camera.lookAt( this.scene.position ); - this.renderer.render( this.scene, this.camera ); + this.renderer.render( this.scene, this.camera ); } module.exports = Globe; From 4cebd0807a1b49227986f6427b1c0423ad90be68 Mon Sep 17 00:00:00 2001 From: Rob Scanlon Date: Sat, 27 Feb 2016 13:52:45 -0500 Subject: [PATCH 2/5] Add ability to click labels --- build/encom-globe.js | 107 +++++++++++++++++++++++++++++---------- build/encom-globe.min.js | 33 ++++++------ display/display-data.js | 32 ++++++------ display/display.js | 24 ++++++--- src/Globe.js | 88 +++++++++++++++++++++++--------- src/Pin.js | 11 +++- 6 files changed, 205 insertions(+), 90 deletions(-) diff --git a/build/encom-globe.js b/build/encom-globe.js index 9e3d2ae..97738f6 100644 --- a/build/encom-globe.js +++ b/build/encom-globe.js @@ -44156,7 +44156,7 @@ var addInitialData = function(){ return; } while(this.data.length > 0 && this.firstRunTime + (next = this.data.pop()).when < Date.now()){ - this.addPin(next.lat, next.lng, next.label); + this.addPin(next.lat, next.lng, next.label, next.id); } if(this.firstRunTime + next.when >= Date.now()){ @@ -44384,32 +44384,68 @@ var createIntroLines = function(){ }; var createMouseBehaviors = function(globe){ - var mouseDown = false, - mousePos = 0, - lastTime = Date.now(), - mouseTimeout; - - globe.domElement.onmousedown = function(e){ mouseDown = true; mousePos = e.clientX; lastTime = Date.now();}; - globe.domElement.onmouseup = function(e){ mouseDown = false; globe.resetRotationSpeed()}; - globe.domElement.onmouseleave = function(e){ mouseDown = false; globe.resetRotationSpeed();}; - - var onmousemove = function(e, secondCall){ - var diff = Date.now() - lastTime; - if(mouseDown && diff){ - - globe.setRotationSpeed(((e.clientX-mousePos)/globe.width) / (diff/1000)); - - lastTime = Date.now(); - mousePos = e.clientX; - clearTimeout(mouseTimeout); - if(!secondCall){ - mouseTimeout = setTimeout(function(){onmousemove(e, true)},100); - } + var mouseDown = false, + mousePos = 0, + lastTime = Date.now(), + movedSinceMouseDown = false, + mouseTimeout, + mouseVector = new THREE.Vector3(0,0,0), + projector = new THREE.Projector(); + + + globe.domElement.onmousedown = function(e){ mouseDown = true; mousePos = e.clientX; lastTime = Date.now(); movedSinceMouseDown=false;}; + globe.domElement.onmouseup = function(e){ mouseDown = false; globe.resetRotationSpeed()}; + globe.domElement.onmouseleave = function(e){ mouseDown = false; globe.resetRotationSpeed();}; + + var onmousemove = function(e, secondCall){ + + mouseVector.x = 2 * (e.clientX / globe.width) - 1; + mouseVector.y = 1 - 2 *(e.clientY / globe.height); + + var diff = Date.now() - lastTime; + if(mouseDown && diff){ + movedSinceMouseDown = true; + + globe.setRotationSpeed(((e.clientX-mousePos)/globe.width) / (diff/1000)); + + lastTime = Date.now(); + mousePos = e.clientX; + clearTimeout(mouseTimeout); + if(!secondCall){ + mouseTimeout = setTimeout(function(){onmousemove(e, true)},100); + } + } + }; + + var onclick = function (e) { + if(!movedSinceMouseDown){ + var raycaster = projector.pickingRay( mouseVector.clone(), globe.camera ); + var intersects = raycaster.intersectObjects(globe.scene.children); + var minDistance = globe.cameraDistance * 1.1; + var closestObjectId = null; + + for(var i = 0; i 0)){ + var objectDistance = globe.camera.position.distanceTo(intersects[i].object.position); + + if(objectDistance < minDistance){ + minDistance = objectDistance; + closestObjectId = objName; + } + } + } + + if(closestObjectId != null && globe.clickHandler){ + globe.clickHandler(closestObjectId); + } + } } - }; - globe.domElement.onmousemove = onmousemove; -} + globe.domElement.onmousemove = onmousemove; + globe.domElement.onclick = onclick; + +}; /* globe constructor */ @@ -44531,7 +44567,7 @@ Globe.prototype.destroy = function(callback){ }; -Globe.prototype.addPin = function(lat, lon, text){ +Globe.prototype.addPin = function(lat, lon, text, id){ lat = parseFloat(lat); lon = parseFloat(lon); @@ -44539,7 +44575,8 @@ Globe.prototype.addPin = function(lat, lon, text){ var opts = { lineColor: this.pinColor, topColor: this.pinColor, - font: this.font + font: this.font, + id: id } var altitude = 1.2; @@ -44810,6 +44847,11 @@ Globe.prototype.tick = function(){ this.camera.lookAt( this.scene.position ); this.renderer.render( this.scene, this.camera ); + +} + +Globe.prototype.setClickHandler = function(clickHandler){ + this.clickHandler = clickHandler; } module.exports = Globe; @@ -45115,7 +45157,8 @@ var Pin = function(lat, lon, text, altitude, scene, smokeProvider, _opts){ font: "Inconsolata", showLabel: (text.length > 0), showTop: (text.length > 0), - showSmoke: (text.length > 0) + showSmoke: (text.length > 0), + id: null } var lineMaterial, @@ -45177,6 +45220,7 @@ var Pin = function(lat, lon, text, altitude, scene, smokeProvider, _opts){ fog: true }); + this.labelSprite = new THREE.Sprite(labelMaterial); this.labelSprite.position = {x: point.x*altitude*1.1, y: point.y*altitude + (point.y < 0 ? -15 : 30), z: point.z*altitude*1.1}; this.labelSprite.scale.set(labelCanvas.width, labelCanvas.height); @@ -45228,6 +45272,13 @@ var Pin = function(lat, lon, text, altitude, scene, smokeProvider, _opts){ _this.lineGeometry.verticesNeedUpdate = true; }).start(); + /* add in ids for later reference */ + if(this.opts.id !== null && this.opts.id !== undefined){ + this.labelSprite.name = this.opts.id; + this.line.name = this.opts.id; + this.topSprite.name = this.opts.id; + } + /* add to scene */ this.scene.add(this.labelSprite); diff --git a/build/encom-globe.min.js b/build/encom-globe.min.js index 1bd1b8e..c3a52b3 100644 --- a/build/encom-globe.min.js +++ b/build/encom-globe.min.js @@ -1,15 +1,18 @@ -!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g=j;j++){o=p,p=q[j].subdivide(r[j],j,l);for(var s=0;j>s;s++){var t=new d(o[s],p[s],p[s+1]);m.push(t),s>0&&(t=new d(o[s-1],o[s],p[s]),m.push(t))}}k=m;var u={};for(var v in i){var w=i[v].project(a);u[w]=w}i=u,this.tiles=[];for(var v in i)this.tiles.push(new c(i[v],f))};b.exports=f},{"./face":2,"./point":4,"./tile":5}],4:[function(a,b){var c=function(a,b,c){void 0!==a&&void 0!==b&&void 0!==c&&(this.x=a,this.y=b,this.z=c),this.faces=[]};c.prototype.subdivide=function(a,b,d){var e=[];e.push(this);for(var f=1;b>f;f++){var g=new c(this.x*(1-f/b)+a.x*(f/b),this.y*(1-f/b)+a.y*(f/b),this.z*(1-f/b)+a.z*(f/b));g=d(g),e.push(g)}return e.push(a),e},c.prototype.segment=function(a,b){var d=new c;return b=Math.max(.01,Math.min(1,b)),d.x=a.x*(1-b)+this.x*b,d.y=a.y*(1-b)+this.y*b,d.z=a.z*(1-b)+this.z*b,d},c.prototype.midpoint=function(a){return this.segment(a,.5)},c.prototype.project=function(a,b){void 0==b&&(b=1),b=Math.max(0,Math.min(1,b));var c=(this.y/this.x,this.z/this.x,this.z/this.y,Math.sqrt(Math.pow(this.x,2)+Math.pow(this.y,2)+Math.pow(this.z,2))),d=a/c;return this.x=this.x*d*b,this.y=this.y*d*b,this.z=this.z*d*b,this},c.prototype.registerFace=function(a){this.faces.push(a)},c.prototype.getOrderedFaces=function(){for(var a=this.faces.slice(),b=[],c=0;ca?360+a:a}function d(a){return a>>>0}function e(a){return a.replace(/^\s+/,"").replace(/\s+$/,"").toLowerCase()}function f(a,b){return Array.prototype.slice.call(a,b)}function g(a,b,c){return a>b?c>a?a:c:b}function h(a,b,c){return(1-c)*a+c*b}function i(a){return a=Math.round(255*a),a>0?255>a?255&a:255:0}function j(a){return a/255}function k(a,b,c){var d,e,f=Math.max(a,b,c),g=Math.min(a,b,c),h=(f+g)/2;if(f==g)d=e=0;else{var i=f-g;switch(e=h>.5?i/(2-f-g):i/(f+g),f){case a:d=(b-c)/i+(c>b?6:0);break;case b:d=(c-a)/i+2;break;case c:d=(a-b)/i+4}d/=6}return[d,e,h]}function l(a,b,c){function d(a,b,c){return 0>c&&(c+=1),c>1&&(c-=1),1/6>c?a+6*(b-a)*c:.5>c?b:2/3>c?a+(b-a)*(2/3-c)*6:a}var e,f,g;if(0==b)e=f=g=c;else{var h=.5>c?c*(1+b):c+b-c*b,i=2*c-h;e=d(i,h,a+1/3),f=d(i,h,a),g=d(i,h,a-1/3)}return[e,f,g]}function m(a){for(var b=[parseInt(a.substr(1,1),16),parseInt(a.substr(2,1),16),parseInt(a.substr(3,1),16),1],c=0;3>c;++c)b[c]=(16*b[c]+b[c])/255;return b}function n(a){return[parseInt(a.substr(1,2),16)/255,parseInt(a.substr(3,2),16)/255,parseInt(a.substr(5,2),16)/255,1]}function o(a){var b,c,d=a[0],e=a[1],f=a[2],g=Math.min(Math.min(d,e),f),h=Math.max(Math.max(d,e),f),i=h;return h==g?c=0:h==d?c=60*((e-f)/(h-g))%360:h==e?c=60*((f-d)/(h-g))+120:h==f&&(c=60*((d-e)/(h-g))+240),0>c&&(c+=360),b=0==h?0:1-g/h,[Math.round(c),Math.round(100*b),Math.round(100*i),a[3]]}function p(b){var c=a(b[0]),d=b[1],e=b[2],d=d/100,e=e/100,f=Math.floor(c/60%6),g=c/60-f,h=e*(1-d),i=e*(1-g*d),j=e*(1-(1-g)*d),k=[];switch(f){case 0:k=[e,j,h];break;case 1:k=[i,e,h];break;case 2:k=[h,e,j];break;case 3:k=[h,i,e];break;case 4:k=[j,h,e];break;case 5:k=[e,h,i]}return[k[0],k[1],k[2],b[3]]}function q(b){var c=k(b[0],b[1],b[2]);return c[0]=a(Math.floor(360*c[0])),c[1]=Math.floor(100*c[1]),c[2]=Math.floor(100*c[2]),c}function r(a){var b=q(a);return b.push(a[3]),b}function s(a){var b=parseFloat(a[0])/360,c=parseFloat(a[1])/100,d=parseFloat(a[2])/100,e=l(b,c,d);return[e[0],e[1],e[2],parseFloat(a[3])]}function t(a){this._value=a}function u(a,b){if(void 0==b)return i(this._value[a]);var c=f(this._value,0);if("string"!=typeof b){var d=this.clone();return d._value[a]=b,d}var e;if(e=b.match(/^([+\-\\*]=?)([0-9.]+)/)){var g=e[1],h=parseFloat(e[2]);switch(g[0]){case"+":c[a]+=h/255;break;case"-":c[a]-=h/255;break;case"*":c[a]*=h}return"="==g[1]?(this._value=c,this):new t(c)}}function v(b){return function(){function c(c,d,e){e=parseFloat(e);var f=o(c._value),g=0;switch(d){case"=":f[b]=e,g=1;break;case"+":f[b]+=e,g=1;break;case"+=":f[b]+=e;break;case"-":f[b]-=e,g=1;break;case"-=":f[b]-=e;break;case"*":f[b]*=e,g=1;break;case"*=":f[b]*=e;break;default:throw"Bad op "+d}return 0==b?f[b]=a(f[b]):(1==b||2==b)&&(f[b]<0?f[b]=0:f[b]>99&&(f[b]=99)),g&&(c=c.clone()),c._value=p(f),c}if(0==arguments.length)return o(this._value)[b];if(1==arguments.length){var d;return"string"==typeof arguments[0]&&(d=arguments[0].match(/^([\+\-\*]=?)([0-9.]+)/))?c(this,d[1],d[2]):c(this,"=",arguments[0])}return 2==arguments.length?c(this,arguments[0],arguments[1]):void 0}}var w={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,216],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[216,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},x={byteOrPercent:function(a){var b;return"string"==typeof a&&(b=a.match(/^([0-9]+)%$/))?Math.floor(255*parseFloat(b[1])/100):parseFloat(a)},floatOrPercent:function(a){var b;return"string"==typeof a&&(b=a.match(/^([0-9]+)%$/))?parseFloat(b[1])/100:parseFloat(a)},numberOrPercent:function(a,b){var c;return"string"==typeof a&&(c=a.match(/^([0-9]+)%$/))?parseFloat(c[1])/100*b:parseFloat(a)},rgba:function(a){for(var b=0;3>b;++b)a[b]=j(x.byteOrPercent(a[b]));return a[3]=x.floatOrPercent(a[b]),new t(a)},rgba8:function(a){return new t([j(x.byteOrPercent(a[0])),j(x.byteOrPercent(a[1])),j(x.byteOrPercent(a[2])),j(x.byteOrPercent(a[3]))])},float3:function(a){for(var b=0;3>b;++b)a[b]=x.floatOrPercent(a[b]);return a[3]=1,new t(a)},float4:function(a){for(var b=0;3>b;++b)a[b]=x.floatOrPercent(a[b]);return a[3]=x.floatOrPercent(a[b]),new t(a)},hsla:function(a){return a[0]=x.numberOrPercent(a[0],360),a[1]=x.numberOrPercent(a[1],100),a[2]=x.numberOrPercent(a[2],100),a[3]=x.numberOrPercent(a[3],1),new t(s(a))},hsva:function(b){return b[0]=a(parseFloat(b[0])),b[1]=Math.max(0,Math.min(100,parseFloat(b[1]))),b[2]=Math.max(0,Math.min(100,parseFloat(b[2]))),b[3]=x.floatOrPercent(b[3]),new t(p(b))}},y={keyword:{},hex3:{},hex7:{},rgb:{parse:function(a){return a=a.slice(0),a.push(1),x.rgba(a)}},rgba:{parse:x.rgba},hsl:{parse:function(a){return a=a.slice(0),a.push(1),x.hsla(a)}},hsla:{parse:x.hsla},hsv:{parse:function(a){return a=a.slice(0),a.push(1),x.hsva(a)}},hsva:{parse:x.hsva},rgb8:{parse:function(a){return a=a.slice(0),a.push(1),x.rgba(a)}},rgba8:{parse:function(a){return x.rgba8(a)}},packed_rgba:{parse:function(a){return a=[a>>24&255,a>>16&255,a>>8&255,(255&a)/255],x.rgba(a)},output:function(a){return d(i(a[0])<<24|i(a[1])<<16|i(a[2])<<8|i(a[3]))}},packed_argb:{parse:function(a){return a=[a>>16&255,a>>8&255,a>>0&255,(a>>24&255)/255],x.rgba(a)},output:function(a){return d(i(a[3])<<24|i(a[0])<<16|i(a[1])<<8|i(a[2]))}},float3:{parse:x.float3},float4:{parse:x.float4}},z=function(){var a=null;if(arguments[0]instanceof t)return new t(arguments[0]._value);if("string"==typeof arguments[0]){var b=arguments[0][0];if("#"==b){if(a=arguments[0].match(/^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/i))return new t(m(a[0]));if(a=arguments[0].match(/^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/i))return new t(n(a[0]))}else{if(a=y[arguments[0].toLowerCase()])return a.parse(2==arguments.length?arguments[1]:f(arguments,1));if(a=arguments[0].match(/^\s*([A-Z][A-Z0-9_]+)\s*\(\s*([\-0-9A-FX]+)\s*\)\s*$/i)){var c=y[a[1].toLowerCase()];return c.parse(a[2])}if(a=arguments[0].match(/^\s*([A-Z][A-Z0-9]+)\s*\(\s*([0-9\.]+%?)\s*,\s*([0-9\.]+%?)\s*,\s*([0-9\.]+%?)\s*(,\s*([0-9\.]+%?)\s*)?\)\s*$/i)){var c=y[a[1].toLowerCase()];if(void 0===a[5]){var d=[a[2],a[3],a[4]];return c.parse(d)}var d=[a[2],a[3],a[4],a[6]];return c.parse(d)}if(1==arguments.length&&(a=w[e(arguments[0])])){var d=a;return new t([j(d[0]),j(d[1]),j(d[2]),1])}}}throw"Could not parse color '"+arguments[0]+"'"},A={white:z("white"),black:z("black"),gray:z("gray")},B={clone:function(){return new t(this._value.slice(0))},html:function(){var a=this,b=this._value,c={hex3:function(){return a.hex3()},hex6:function(){return a.hex6()},rgb:function(){return"rgb("+a.rgb().join(",")+")"},rgba:function(){return"rgba("+a.rgba().join(",")+")"},hsl:function(){return"hsl("+q(b).join(",")+")"},hsla:function(){return"hsla("+r(b).join(",")+")"},keyword:function(){var a,c=195076;for(C in w){for(var d=w[C],e=0,f=0;3>f;++f){var g=b[f]-j(d[f]);e+=g*g}c>e&&(a=C,c=e)}return a}},d=arguments[0]||"rgba";return c[d]()},red:function(){return u.call(this,0,arguments[0])},green:function(){return u.call(this,1,arguments[0])},blue:function(){return u.call(this,2,arguments[0])},alpha:function(){return 1==arguments.length?(c=this.clone(),c._value[3]=x.floatOrPercent(arguments[0]),c):this._value[3]},alpha8:function(){return 1==arguments.length?(c=this.clone(),c._value[3]=x.byteOrPercent(arguments[0])/255,c):Math.floor(255*this._value[3])},grayvalue:function(){var a=this._value;return(a[0]+a[1]+a[2])/3},grayvalue8:function(){return i(this.grayvalue())},luminance:function(){var a=this._value;return.2126*a[0]+.7152*a[1]+.0722*a[2]},luminance8:function(){return i(this.luminance())},hsv:function(){return o(this._value).slice(0,3)},hsva:function(){return o(this._value)},packed_rgba:function(){return y.packed_rgba.output(this._value)},packed_argb:function(){return y.packed_argb.output(this._value)},hue:v(0),saturation:v(1),value:v(2),clamp:function(){var a=this._value;return new t([g(a[0],0,1),g(a[1],0,1),g(a[2],0,1),g(a[3],0,1)])},blend:function(a,b){"number"!=typeof b&&(b=x.floatOrPercent(b));var c=this,d=z(a);return new t([h(c._value[0],d._value[0],b),h(c._value[1],d._value[1],b),h(c._value[2],d._value[2],b),h(c._value[3],d._value[3],b)])},add:function(a){var b=this._value,c=z(a)._value;return new t([b[0]+c[0]*c[3],b[1]+c[1]*c[3],b[2]+c[2]*c[3],b[3]])},inc:function(a){var b=this._value,c=z(a)._value;return b[0]+=c[0]*c[3],b[1]+=c[1]*c[3],b[2]+=c[2]*c[3],this},dec:function(a){var b=this._value,c=z(a)._value;return b[0]-=c[0]*c[3],b[1]-=c[1]*c[3],b[2]-=c[2]*c[3],this},subtract:function(a){var b=this._value,c=z(a)._value;return new t([b[0]-c[0]*c[3],b[1]-c[1]*c[3],b[2]-c[2]*c[3],b[3]])},multiply:function(a){var b=this._value,c=z(a)._value;return new t([b[0]*c[0],b[1]*c[1],b[2]*c[2],b[3]*c[3]])},scale:function(a){var b=this._value;return new t([b[0]*a,b[1]*a,b[2]*a,b[3]])},xor:function(a){var b=this.rgba8(),c=z(a).rgba8();return z("rgba8",b[0]^c[0],b[1]^c[1],b[2]^c[2],b[3])},tint:function(a){return this.blend(A.white,a)},shade:function(a){return this.blend(A.black,a)},tone:function(a){return this.blend(A.gray,a)},complement:function(){var b=this.hsva();return b[0]=a(b[0]+180),new t(p(b))},triad:function(){return[new t(this._value),this.hue("+120"),this.hue("+240")]},hueSet:function(){for(var a=0,b=[],c=100;c>=30;c-=35)for(var d=100;d>=30;d-=35)b.push(this.hue("+",a).saturation(c).value(d));return b},hueRange:function(a,b){for(var c=this.hue(),d=[],e=0;b>e;++e){var f=c+2*(e/(b-1)-.5)*a;d.push(this.hue("=",f))}return d},contrastWhiteBlack:function(){return z(this.value()<50?"white":"black")},contrastGray:function(){var a=this.hsva(),b=a[2]<30?a[2]+20:a[2]-20;return new t(p([a[0],0,b,a[3]]))},hex3:function(){function a(a){return Math.min(Math.round(i(a)/16),15).toString(16)}return"#"+a(this._value[0])+a(this._value[1])+a(this._value[2])},hex6:function(){function a(a){var b=i(a).toString(16);return b.length<2?"0"+b:b}return"#"+a(this._value[0])+a(this._value[1])+a(this._value[2])},rgb:function(){var a=this._value;return[i(a[0]),i(a[1]),i(a[2])]},rgba:function(){var a=this._value;return[i(a[0]),i(a[1]),i(a[2]),a[3]]},rgb8:function(){var a=this._value;return[i(a[0]),i(a[1]),i(a[2])]},rgba8:function(){var a=this._value;return[i(a[0]),i(a[1]),i(a[2]),this.alpha8()]},float3:function(){return[this._value[0],this._value[1],this._value[2]]},float4:function(){return[this._value[0],this._value[1],this._value[2],this._value[3]]}};B.sub=B.subtract,B.mul=B.multiply;for(var C in B)t.prototype[C]=B[C];z.float3=function(a,b,c){return new t([a,b,c,1])},z.float4=function(a,b,c,d){return new t([a,b,c,d])},z.version="0.2.4",z.Color=t,"undefined"!=typeof b&&b.exports?b.exports=z:"undefined"!=typeof window&&(window.pusher=window.pusher||{},window.pusher.color=z)}()},{}],7:[function(a,b){!function c(a,d,e){function f(a,b){return this instanceof f?(g(a)?(b=a[1],a=a[0]):"object"==typeof a&&a&&(b=a.y,a=a.x),this.x=f.clean(a||0),void(this.y=f.clean(b||0))):new f(a,b)}var g=function(a){return"[object Array]"===Object.prototype.toString.call(a)};f.prototype={change:function(a){if(a)this.observers?this.observers.push(a):this.observers=[a];else if(this.observers)for(var b=this.observers.length-1;b>=0;b--)this.observers[b](this);return this},ignore:function(a){if(this.observers)for(var b=this.observers,c=b.length;c--;)b[c]===a&&b.splice(c,1);return this},set:function(a,b,c){return"number"!=typeof a&&(c=b,b=a.y,a=a.x),this.x===a&&this.y===b?this:(this.x=f.clean(a),this.y=f.clean(b),c!==!1?this.change():void 0)},zero:function(){return this.set(0,0)},clone:function(){return new this.constructor(this.x,this.y)},negate:function(a){return a?new this.constructor(-this.x,-this.y):this.set(-this.x,-this.y)},add:function(a,b){return b?new this.constructor(this.x+a.x,this.y+a.y):(this.x+=a.x,this.y+=a.y,this.change())},subtract:function(a,b){return b?new this.constructor(this.x-a.x,this.y-a.y):(this.x-=a.x,this.y-=a.y,this.change())},multiply:function(a,b){var c,d;return"number"!=typeof a?(c=a.x,d=a.y):c=d=a,b?new this.constructor(this.x*c,this.y*d):this.set(this.x*c,this.y*d)},rotate:function(a,b,c){var d,e,f=this.x,g=this.y,h=Math.cos(a),i=Math.sin(a);return b=b?-1:1,d=h*f-b*i*g,e=b*i*f+h*g,c?new this.constructor(d,e):this.set(d,e)},length:function(){var a=this.x,b=this.y;return Math.sqrt(a*a+b*b)},lengthSquared:function(){var a=this.x,b=this.y;return a*a+b*b},distance:function(a){var b=this.x-a.x,c=this.y-a.y;return Math.sqrt(b*b+c*c)},normalize:function(a){var b=this.length(),c=bc?c:e,h=f>d?d:f;return b?new this.constructor(g,h):this.set(g,h)},max:function(a,b){var c=this.x,d=this.y,e=a.x,f=a.y,g=c>e?c:e,h=d>f?d:f;return b?new this.constructor(g,h):this.set(g,h)},clamp:function(a,b,c){var d=this.min(b,!0).max(a);return c?d:this.set(d.x,d.y)},lerp:function(a,b){return this.add(a.subtract(this,!0).multiply(b),!0)},skew:function(){return new this.constructor(-this.y,this.x)},dot:function(a){return f.clean(this.x*a.x+a.y*this.y)},perpDot:function(a){return f.clean(this.x*a.y-this.y*a.x)},angleTo:function(a){return Math.atan2(this.perpDot(a),this.dot(a))},divide:function(a,b){var c,d;if("number"!=typeof a?(c=a.x,d=a.y):c=d=a,0===c||0===d)throw new Error("division by zero");if(isNaN(c)||isNaN(d))throw new Error("NaN detected");return b?new this.constructor(this.x/c,this.y/d):this.set(this.x/c,this.y/d)},isPointOnLine:function(a,b){return(a.y-this.y)*(a.x-b.x)===(a.y-b.y)*(a.x-this.x)},toArray:function(){return[this.x,this.y]},fromArray:function(a){return this.set(a[0],a[1])},toJSON:function(){return{x:this.x,y:this.y}},toString:function(){return"("+this.x+", "+this.y+")"},constructor:f},f.fromArray=function(a,b){return new(b||f)(a[0],a[1])},f.precision=d||8;var h=Math.pow(10,f.precision);return f.clean=a||function(a){if(isNaN(a))throw new Error("NaN detected");if(!isFinite(a))throw new Error("Infinity detected");return Math.round(a)===a?a:Math.round(a*h)/h},f.inject=c,a||(f.fast=c(function(a){return a}),"undefined"!=typeof b&&"object"==typeof b.exports?b.exports=f:window.Vec2=window.Vec2||f),f}()},{}],8:[function(a,b){var c,d=a("vec2"),e=a("./quadtree2helper"),f=a("./quadtree2validator"),g=a("./quadtree2quadrant");c=function(a,b,c){var h,i={objects_:{},quadrants_:{},ids_:1,quadrantIds_:1,autoId_:!0,inited_:!1,debug_:!1,size_:void 0,root_:void 0,quadrantObjectsLimit_:void 0,quadrantLevelLimit_:void 0,quadrantSizeLimit_:void 0},j=new f,k={p:"pos_",r:"rad_",id:"id_"},l={data:{necessary:{size_:j.isVec2,quadrantObjectsLimit_:j.isNumber,quadrantLevelLimit_:j.isNumber}},k:{necessary:{p:j.isVec2},c:{necessary:{r:j.isNumber}}}},m={nextId:function(){return i.ids_++},nextQuadrantId:function(a){var b=i.quadrantIds_;return i.quadrantIds_+=a||4,b},hasCollision:function(a,b){return a[k.r]+b[k.r]>a[k.p].distance(b[k.p])},removeQuadrantParentQuadrants:function(a,b){a.parent_&&b[a.parent_.id_]&&(delete b[a.parent_.id_],m.removeQuadrantParentQuadrants(a.parent_,b))},getSubtreeTopQuadrant:function p(a,b){return a.parent_&&b[a.parent_.id_]?p(a.parent_,b):a},removeQuadrantChildtree:function(a,b){var c,d=a.getChildren();for(c=0;ci.quadrantObjectsLimit_)){for(a.refactoring_=!0,b=0;b0?!1:(this.children_.push(new c(this.leftTop_,this.rad_,a++,this),new c(this.topMid_,this.rad_,a++,this),new c(this.leftMid_,this.rad_,a++,this),new c(this.center_,this.rad_,a++,this)),a)},looseChildren:function(){this.children_=[]},addObjects:function(a){var b;for(b in a)this.addObject(b,a[b])},addObject:function(a,b){this.objectCount_++,this.objects_[a]=b},removeObjects:function(a,b){var c;a||(a=[]);for(c in this.objects_)a.push({obj:this.objects_[c],quadrant:this}),delete this.objects_[c];return this.objectCount_=0,b&&1!==b||this.parent_&&this.parent_.removeObjects(a,1),b&&-1!==b||this.children_.forEach(function(b){b.removeObjects(a,-1)}),a},removeObject:function(a){var b=this.objects_[a];return this.objectCount_--,delete this.objects_[a],b},getObjectCountForLimit:function(){var a,b,c={};for(b in this.objects_)c[b]=!0;for(a=0;athis.rad_.x+b?!1:c.y>this.rad_.y+b?!1:c.x<=this.rad_.x?!0:c.y<=this.rad_.y?!0:(cornerDistSq=Math.pow(c.x-this.rad_.x,2)+Math.pow(c.y-this.rad_.y,2),cornerDistSq<=Math.pow(b,2))},hasChildren:function(){return 0!==this.getChildCount()},getChildCount:function(a){var b=this.children_.length;return a&&this.children_.forEach(function(c){b+=c.getChildCount(a)}),b},getChildren:function(a,b){return b||(b=[]),b.push.apply(b,this.children_),a&&this.children_.forEach(function(c){c.getChildren(a,b)}),b},getObjectsUp:function(a){var b;if(!a.quadrants[this.id_]){a.quadrants[this.id_]=!0;for(b in this.objects_)a.objects[b]=this.objects_[b];this.parent_&&this.parent_.getObjectsUp(a)}},getObjectsDown:function(a){var b;if(!a.quadrants[this.id_]){a.quadrants[this.id_]=!0;for(b in this.objects_)a.objects[b]=this.objects_[b];for(b=0;b>16&255)/255,this.g=(a>>8&255)/255,this.b=(255&a)/255,this},setRGB:function(a,b,c){return this.r=a,this.g=b,this.b=c,this},setHSL:function(a,b,c){if(0===b)this.r=this.g=this.b=c;else{var d=function(a,b,c){return 0>c&&(c+=1),c>1&&(c-=1),1/6>c?a+6*(b-a)*c:.5>c?b:2/3>c?a+6*(b-a)*(2/3-c):a},e=.5>=c?c*(1+b):c+b-c*b,f=2*c-e;this.r=d(f,e,a+1/3),this.g=d(f,e,a),this.b=d(f,e,a-1/3)}return this},setStyle:function(a){if(/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test(a)){var b=/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec(a);return this.r=Math.min(255,parseInt(b[1],10))/255,this.g=Math.min(255,parseInt(b[2],10))/255,this.b=Math.min(255,parseInt(b[3],10))/255,this}if(/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test(a)){var b=/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec(a);return this.r=Math.min(100,parseInt(b[1],10))/100,this.g=Math.min(100,parseInt(b[2],10))/100,this.b=Math.min(100,parseInt(b[3],10))/100,this}if(/^\#([0-9a-f]{6})$/i.test(a)){var b=/^\#([0-9a-f]{6})$/i.exec(a);return this.setHex(parseInt(b[1],16)),this}if(/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(a)){var b=/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(a);return this.setHex(parseInt(b[1]+b[1]+b[2]+b[2]+b[3]+b[3],16)),this}return/^(\w+)$/i.test(a)?(this.setHex(e.ColorKeywords[a]),this):void 0},copy:function(a){return this.r=a.r,this.g=a.g,this.b=a.b,this},copyGammaToLinear:function(a){return this.r=a.r*a.r,this.g=a.g*a.g,this.b=a.b*a.b,this},copyLinearToGamma:function(a){return this.r=Math.sqrt(a.r),this.g=Math.sqrt(a.g),this.b=Math.sqrt(a.b),this},convertGammaToLinear:function(){var a=this.r,b=this.g,c=this.b;return this.r=a*a,this.g=b*b,this.b=c*c,this},convertLinearToGamma:function(){return this.r=Math.sqrt(this.r),this.g=Math.sqrt(this.g),this.b=Math.sqrt(this.b),this},getHex:function(){return 255*this.r<<16^255*this.g<<8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(a){var b,c,d=a||{h:0,s:0,l:0},e=this.r,f=this.g,g=this.b,h=Math.max(e,f,g),i=Math.min(e,f,g),j=(i+h)/2;if(i===h)b=0,c=0;else{var k=h-i;switch(c=.5>=j?k/(h+i):k/(2-h-i),h){case e:b=(f-g)/k+(g>f?6:0);break;case f:b=(g-e)/k+2;break;case g:b=(e-f)/k+4}b/=6}return d.h=b,d.s=c,d.l=j,d},getStyle:function(){return"rgb("+(255*this.r|0)+","+(255*this.g|0)+","+(255*this.b|0)+")"},offsetHSL:function(a,b,c){var d=this.getHSL();return d.h+=a,d.s+=b,d.l+=c,this.setHSL(d.h,d.s,d.l),this},add:function(a){return this.r+=a.r,this.g+=a.g,this.b+=a.b,this},addColors:function(a,b){return this.r=a.r+b.r,this.g=a.g+b.g,this.b=a.b+b.b,this},addScalar:function(a){return this.r+=a,this.g+=a,this.b+=a,this},multiply:function(a){return this.r*=a.r,this.g*=a.g,this.b*=a.b,this},multiplyScalar:function(a){return this.r*=a,this.g*=a,this.b*=a,this},lerp:function(a,b){return this.r+=(a.r-this.r)*b,this.g+=(a.g-this.g)*b,this.b+=(a.b-this.b)*b,this},equals:function(a){return a.r===this.r&&a.g===this.g&&a.b===this.b},fromArray:function(a){return this.r=a[0],this.g=a[1],this.b=a[2],this},toArray:function(){return[this.r,this.g,this.b]},clone:function(){return(new e.Color).setRGB(this.r,this.g,this.b)}},e.ColorKeywords={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},e.Quaternion=function(a,b,c,d){this._x=a||0,this._y=b||0,this._z=c||0,this._w=void 0!==d?d:1},e.Quaternion.prototype={constructor:e.Quaternion,_x:0,_y:0,_z:0,_w:0,_euler:void 0,_updateEuler:function(){void 0!==this._euler&&this._euler.setFromQuaternion(this,void 0,!1)},get x(){return this._x},set x(a){this._x=a,this._updateEuler()},get y(){return this._y},set y(a){this._y=a,this._updateEuler()},get z(){return this._z},set z(a){this._z=a,this._updateEuler()},get w(){return this._w},set w(a){this._w=a,this._updateEuler()},set:function(a,b,c,d){return this._x=a,this._y=b,this._z=c,this._w=d,this._updateEuler(),this},copy:function(a){return this._x=a._x,this._y=a._y,this._z=a._z,this._w=a._w,this._updateEuler(),this},setFromEuler:function(a,b){if(a instanceof e.Euler==!1)throw new Error("ERROR: Quaternion's .setFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.");var c=Math.cos(a._x/2),d=Math.cos(a._y/2),f=Math.cos(a._z/2),g=Math.sin(a._x/2),h=Math.sin(a._y/2),i=Math.sin(a._z/2);return"XYZ"===a.order?(this._x=g*d*f+c*h*i,this._y=c*h*f-g*d*i,this._z=c*d*i+g*h*f,this._w=c*d*f-g*h*i):"YXZ"===a.order?(this._x=g*d*f+c*h*i,this._y=c*h*f-g*d*i,this._z=c*d*i-g*h*f,this._w=c*d*f+g*h*i):"ZXY"===a.order?(this._x=g*d*f-c*h*i,this._y=c*h*f+g*d*i,this._z=c*d*i+g*h*f,this._w=c*d*f-g*h*i):"ZYX"===a.order?(this._x=g*d*f-c*h*i,this._y=c*h*f+g*d*i,this._z=c*d*i-g*h*f,this._w=c*d*f+g*h*i):"YZX"===a.order?(this._x=g*d*f+c*h*i,this._y=c*h*f+g*d*i,this._z=c*d*i-g*h*f,this._w=c*d*f-g*h*i):"XZY"===a.order&&(this._x=g*d*f-c*h*i,this._y=c*h*f-g*d*i,this._z=c*d*i+g*h*f,this._w=c*d*f+g*h*i),b!==!1&&this._updateEuler(),this},setFromAxisAngle:function(a,b){var c=b/2,d=Math.sin(c);return this._x=a.x*d,this._y=a.y*d,this._z=a.z*d,this._w=Math.cos(c),this._updateEuler(),this},setFromRotationMatrix:function(a){var b,c=a.elements,d=c[0],e=c[4],f=c[8],g=c[1],h=c[5],i=c[9],j=c[2],k=c[6],l=c[10],m=d+h+l;return m>0?(b=.5/Math.sqrt(m+1),this._w=.25/b,this._x=(k-i)*b,this._y=(f-j)*b,this._z=(g-e)*b):d>h&&d>l?(b=2*Math.sqrt(1+d-h-l),this._w=(k-i)/b,this._x=.25*b,this._y=(e+g)/b,this._z=(f+j)/b):h>l?(b=2*Math.sqrt(1+h-d-l),this._w=(f-j)/b,this._x=(e+g)/b,this._y=.25*b,this._z=(i+k)/b):(b=2*Math.sqrt(1+l-d-h),this._w=(g-e)/b,this._x=(f+j)/b,this._y=(i+k)/b,this._z=.25*b),this._updateEuler(),this},inverse:function(){return this.conjugate().normalize(),this},conjugate:function(){return this._x*=-1,this._y*=-1,this._z*=-1,this._updateEuler(),this},lengthSq:function(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w},length:function(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)},normalize:function(){var a=this.length();return 0===a?(this._x=0,this._y=0,this._z=0,this._w=1):(a=1/a,this._x=this._x*a,this._y=this._y*a,this._z=this._z*a,this._w=this._w*a),this},multiply:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Quaternion's .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z,f=a._w,g=b._x,h=b._y,i=b._z,j=b._w;return this._x=c*j+f*g+d*i-e*h,this._y=d*j+f*h+e*g-c*i,this._z=e*j+f*i+c*h-d*g,this._w=f*j-c*g-d*h-e*i,this._updateEuler(),this},multiplyVector3:function(a){return console.warn("DEPRECATED: Quaternion's .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead."),a.applyQuaternion(this)},slerp:function(a,b){var c=this._x,d=this._y,e=this._z,f=this._w,g=f*a._w+c*a._x+d*a._y+e*a._z;if(0>g?(this._w=-a._w,this._x=-a._x,this._y=-a._y,this._z=-a._z,g=-g):this.copy(a),g>=1)return this._w=f,this._x=c,this._y=d,this._z=e,this;var h=Math.acos(g),i=Math.sqrt(1-g*g);if(Math.abs(i)<.001)return this._w=.5*(f+this._w),this._x=.5*(c+this._x),this._y=.5*(d+this._y),this._z=.5*(e+this._z),this;var j=Math.sin((1-b)*h)/i,k=Math.sin(b*h)/i;return this._w=f*j+this._w*k,this._x=c*j+this._x*k,this._y=d*j+this._y*k,this._z=e*j+this._z*k,this._updateEuler(),this},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w},fromArray:function(a){return this._x=a[0],this._y=a[1],this._z=a[2],this._w=a[3],this._updateEuler(),this},toArray:function(){return[this._x,this._y,this._z,this._w]},clone:function(){return new e.Quaternion(this._x,this._y,this._z,this._w)}},e.Quaternion.slerp=function(a,b,c,d){return c.copy(a).slerp(b,d)},e.Vector2=function(a,b){this.x=a||0,this.y=b||0},e.Vector2.prototype={constructor:e.Vector2,set:function(a,b){return this.x=a,this.y=b,this},setX:function(a){return this.x=a,this},setY:function(a){return this.y=a,this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw new Error("index is out of range: "+a)}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+a)}},copy:function(a){return this.x=a.x,this.y=a.y,this},add:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Vector2's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b)):(this.x+=a.x,this.y+=a.y,this)},addVectors:function(a,b){return this.x=a.x+b.x,this.y=a.y+b.y,this},addScalar:function(a){return this.x+=a,this.y+=a,this},sub:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Vector2's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b)):(this.x-=a.x,this.y-=a.y,this)},subVectors:function(a,b){return this.x=a.x-b.x,this.y=a.y-b.y,this},multiplyScalar:function(a){return this.x*=a,this.y*=a,this},divideScalar:function(a){if(0!==a){var b=1/a;this.x*=b,this.y*=b}else this.x=0,this.y=0;return this},min:function(a){return this.x>a.x&&(this.x=a.x),this.y>a.y&&(this.y=a.y),this},max:function(a){return this.xb.x&&(this.x=b.x),this.yb.y&&(this.y=b.y),this},clampScalar:function(){var a,b;return function(c,d){return void 0===a&&(a=new e.Vector2,b=new e.Vector2),a.set(c,c),b.set(d,d),this.clamp(a,b)}}(),floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},roundToZero:function(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y;return b*b+c*c},setLength:function(a){var b=this.length();return 0!==b&&a!==b&&this.multiplyScalar(a/b),this},lerp:function(a,b){return this.x+=(a.x-this.x)*b,this.y+=(a.y-this.y)*b,this},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a){return this.x=a[0],this.y=a[1],this},toArray:function(){return[this.x,this.y]},clone:function(){return new e.Vector2(this.x,this.y)}},e.Vector3=function(a,b,c){this.x=a||0,this.y=b||0,this.z=c||0},e.Vector3.prototype={constructor:e.Vector3,set:function(a,b,c){return this.x=a,this.y=b,this.z=c,this},setX:function(a){return this.x=a,this},setY:function(a){return this.y=a,this},setZ:function(a){return this.z=a,this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:throw new Error("index is out of range: "+a)}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+a)}},copy:function(a){return this.x=a.x,this.y=a.y,this.z=a.z,this},add:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Vector3's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b)):(this.x+=a.x,this.y+=a.y,this.z+=a.z,this)},addScalar:function(a){return this.x+=a,this.y+=a,this.z+=a,this},addVectors:function(a,b){return this.x=a.x+b.x,this.y=a.y+b.y,this.z=a.z+b.z,this},sub:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Vector3's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b)):(this.x-=a.x,this.y-=a.y,this.z-=a.z,this)},subVectors:function(a,b){return this.x=a.x-b.x,this.y=a.y-b.y,this.z=a.z-b.z,this},multiply:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Vector3's .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(a,b)):(this.x*=a.x,this.y*=a.y,this.z*=a.z,this)},multiplyScalar:function(a){return this.x*=a,this.y*=a,this.z*=a,this},multiplyVectors:function(a,b){return this.x=a.x*b.x,this.y=a.y*b.y,this.z=a.z*b.z,this},applyEuler:function(){var a;return function(b){return b instanceof e.Euler==!1&&console.error("ERROR: Vector3's .applyEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code."),void 0===a&&(a=new e.Quaternion),this.applyQuaternion(a.setFromEuler(b)),this}}(),applyAxisAngle:function(){var a;return function(b,c){return void 0===a&&(a=new e.Quaternion),this.applyQuaternion(a.setFromAxisAngle(b,c)),this}}(),applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z,e=a.elements;return this.x=e[0]*b+e[3]*c+e[6]*d,this.y=e[1]*b+e[4]*c+e[7]*d,this.z=e[2]*b+e[5]*c+e[8]*d,this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=a.elements;return this.x=e[0]*b+e[4]*c+e[8]*d+e[12],this.y=e[1]*b+e[5]*c+e[9]*d+e[13],this.z=e[2]*b+e[6]*c+e[10]*d+e[14],this},applyProjection:function(a){var b=this.x,c=this.y,d=this.z,e=a.elements,f=1/(e[3]*b+e[7]*c+e[11]*d+e[15]);return this.x=(e[0]*b+e[4]*c+e[8]*d+e[12])*f,this.y=(e[1]*b+e[5]*c+e[9]*d+e[13])*f,this.z=(e[2]*b+e[6]*c+e[10]*d+e[14])*f,this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,g=a.z,h=a.w,i=h*b+f*d-g*c,j=h*c+g*b-e*d,k=h*d+e*c-f*b,l=-e*b-f*c-g*d;return this.x=i*h+l*-e+j*-g-k*-f,this.y=j*h+l*-f+k*-e-i*-g,this.z=k*h+l*-g+i*-f-j*-e,this},transformDirection:function(a){var b=this.x,c=this.y,d=this.z,e=a.elements;return this.x=e[0]*b+e[4]*c+e[8]*d,this.y=e[1]*b+e[5]*c+e[9]*d,this.z=e[2]*b+e[6]*c+e[10]*d,this.normalize(),this},divide:function(a){return this.x/=a.x,this.y/=a.y,this.z/=a.z,this},divideScalar:function(a){if(0!==a){var b=1/a;this.x*=b,this.y*=b,this.z*=b}else this.x=0,this.y=0,this.z=0;return this},min:function(a){return this.x>a.x&&(this.x=a.x),this.y>a.y&&(this.y=a.y),this.z>a.z&&(this.z=a.z),this},max:function(a){return this.xb.x&&(this.x=b.x),this.yb.y&&(this.y=b.y),this.zb.z&&(this.z=b.z),this},clampScalar:function(){var a,b;return function(c,d){return void 0===a&&(a=new e.Vector3,b=new e.Vector3),a.set(c,c,c),b.set(d,d,d),this.clamp(a,b)}}(),floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this},roundToZero:function(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this.z=this.z<0?Math.ceil(this.z):Math.floor(this.z),this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){var b=this.length();return 0!==b&&a!==b&&this.multiplyScalar(a/b),this},lerp:function(a,b){return this.x+=(a.x-this.x)*b,this.y+=(a.y-this.y)*b,this.z+=(a.z-this.z)*b,this},cross:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b);var c=this.x,d=this.y,e=this.z;return this.x=d*a.z-e*a.y,this.y=e*a.x-c*a.z,this.z=c*a.y-d*a.x,this},crossVectors:function(a,b){var c=a.x,d=a.y,e=a.z,f=b.x,g=b.y,h=b.z;return this.x=d*h-e*g,this.y=e*f-c*h,this.z=c*g-d*f,this},projectOnVector:function(){var a,b;return function(c){return void 0===a&&(a=new e.Vector3),a.copy(c).normalize(),b=this.dot(a),this.copy(a).multiplyScalar(b)}}(),projectOnPlane:function(){var a;return function(b){return void 0===a&&(a=new e.Vector3),a.copy(this).projectOnVector(b),this.sub(a)}}(),reflect:function(){var a;return function(b){return void 0===a&&(a=new e.Vector3),this.sub(a.copy(b).multiplyScalar(2*this.dot(b)))}}(),angleTo:function(a){var b=this.dot(a)/(this.length()*a.length());return Math.acos(e.Math.clamp(b,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y,d=this.z-a.z;return b*b+c*c+d*d},setEulerFromRotationMatrix:function(){console.error("REMOVED: Vector3's setEulerFromRotationMatrix has been removed in favor of Euler.setFromRotationMatrix(), please update your code.")},setEulerFromQuaternion:function(){console.error("REMOVED: Vector3's setEulerFromQuaternion: has been removed in favor of Euler.setFromQuaternion(), please update your code.")},getPositionFromMatrix:function(a){return console.warn("DEPRECATED: Vector3's .getPositionFromMatrix() has been renamed to .setFromMatrixPosition(). Please update your code."),this.setFromMatrixPosition(a)},getScaleFromMatrix:function(a){return console.warn("DEPRECATED: Vector3's .getScaleFromMatrix() has been renamed to .setFromMatrixScale(). Please update your code."),this.setFromMatrixScale(a)},getColumnFromMatrix:function(a,b){return console.warn("DEPRECATED: Vector3's .getColumnFromMatrix() has been renamed to .setFromMatrixColumn(). Please update your code."),this.setFromMatrixColumn(a,b)},setFromMatrixPosition:function(a){return this.x=a.elements[12],this.y=a.elements[13],this.z=a.elements[14],this},setFromMatrixScale:function(a){var b=this.set(a.elements[0],a.elements[1],a.elements[2]).length(),c=this.set(a.elements[4],a.elements[5],a.elements[6]).length(),d=this.set(a.elements[8],a.elements[9],a.elements[10]).length();return this.x=b,this.y=c,this.z=d,this},setFromMatrixColumn:function(a,b){var c=4*a,d=b.elements;return this.x=d[c],this.y=d[c+1],this.z=d[c+2],this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a){return this.x=a[0],this.y=a[1],this.z=a[2],this},toArray:function(){return[this.x,this.y,this.z]},clone:function(){return new e.Vector3(this.x,this.y,this.z)}},e.Vector4=function(a,b,c,d){this.x=a||0,this.y=b||0,this.z=c||0,this.w=void 0!==d?d:1},e.Vector4.prototype={constructor:e.Vector4,set:function(a,b,c,d){return this.x=a,this.y=b,this.z=c,this.w=d,this},setX:function(a){return this.x=a,this},setY:function(a){return this.y=a,this},setZ:function(a){return this.z=a,this},setW:function(a){return this.w=a,this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw new Error("index is out of range: "+a)}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+a)}},copy:function(a){return this.x=a.x,this.y=a.y,this.z=a.z,this.w=void 0!==a.w?a.w:1,this},add:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Vector4's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b)):(this.x+=a.x,this.y+=a.y,this.z+=a.z,this.w+=a.w,this)},addScalar:function(a){return this.x+=a,this.y+=a,this.z+=a,this.w+=a,this},addVectors:function(a,b){return this.x=a.x+b.x,this.y=a.y+b.y,this.z=a.z+b.z,this.w=a.w+b.w,this},sub:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Vector4's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b)):(this.x-=a.x,this.y-=a.y,this.z-=a.z,this.w-=a.w,this)},subVectors:function(a,b){return this.x=a.x-b.x,this.y=a.y-b.y,this.z=a.z-b.z,this.w=a.w-b.w,this},multiplyScalar:function(a){return this.x*=a,this.y*=a,this.z*=a,this.w*=a,this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=this.w,f=a.elements;return this.x=f[0]*b+f[4]*c+f[8]*d+f[12]*e,this.y=f[1]*b+f[5]*c+f[9]*d+f[13]*e,this.z=f[2]*b+f[6]*c+f[10]*d+f[14]*e,this.w=f[3]*b+f[7]*c+f[11]*d+f[15]*e,this},divideScalar:function(a){if(0!==a){var b=1/a;this.x*=b,this.y*=b,this.z*=b,this.w*=b}else this.x=0,this.y=0,this.z=0,this.w=1;return this},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);return 1e-4>b?(this.x=1,this.y=0,this.z=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b),this},setAxisAngleFromRotationMatrix:function(a){var b,c,d,e,f=.01,g=.1,h=a.elements,i=h[0],j=h[4],k=h[8],l=h[1],m=h[5],n=h[9],o=h[2],p=h[6],q=h[10];if(Math.abs(j-l)s&&r>t?f>r?(c=0,d=.707106781,e=.707106781):(c=Math.sqrt(r),d=u/c,e=v/c):s>t?f>s?(c=.707106781,d=0,e=.707106781):(d=Math.sqrt(s),c=u/d,e=w/d):f>t?(c=.707106781,d=.707106781,e=0):(e=Math.sqrt(t),c=v/e,d=w/e),this.set(c,d,e,b),this}var x=Math.sqrt((p-n)*(p-n)+(k-o)*(k-o)+(l-j)*(l-j));return Math.abs(x)<.001&&(x=1),this.x=(p-n)/x,this.y=(k-o)/x,this.z=(l-j)/x,this.w=Math.acos((i+m+q-1)/2),this},min:function(a){return this.x>a.x&&(this.x=a.x),this.y>a.y&&(this.y=a.y),this.z>a.z&&(this.z=a.z),this.w>a.w&&(this.w=a.w),this},max:function(a){return this.xb.x&&(this.x=b.x),this.yb.y&&(this.y=b.y),this.zb.z&&(this.z=b.z),this.wb.w&&(this.w=b.w),this},clampScalar:function(){var a,b;return function(c,d){return void 0===a&&(a=new e.Vector4,b=new e.Vector4),a.set(c,c,c,c),b.set(d,d,d,d),this.clamp(a,b)}}(),floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this.w=Math.floor(this.w),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this.w=Math.ceil(this.w),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this.w=Math.round(this.w),this},roundToZero:function(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this.z=this.z<0?Math.ceil(this.z):Math.floor(this.z),this.w=this.w<0?Math.ceil(this.w):Math.floor(this.w),this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){var b=this.length();return 0!==b&&a!==b&&this.multiplyScalar(a/b),this},lerp:function(a,b){return this.x+=(a.x-this.x)*b,this.y+=(a.y-this.y)*b,this.z+=(a.z-this.z)*b,this.w+=(a.w-this.w)*b,this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},fromArray:function(a){return this.x=a[0],this.y=a[1],this.z=a[2],this.w=a[3],this},toArray:function(){return[this.x,this.y,this.z,this.w]},clone:function(){return new e.Vector4(this.x,this.y,this.z,this.w)}},e.Euler=function(a,b,c,d){this._x=a||0,this._y=b||0,this._z=c||0,this._order=d||e.Euler.DefaultOrder},e.Euler.RotationOrders=["XYZ","YZX","ZXY","XZY","YXZ","ZYX"],e.Euler.DefaultOrder="XYZ",e.Euler.prototype={constructor:e.Euler,_x:0,_y:0,_z:0,_order:e.Euler.DefaultOrder,_quaternion:void 0,_updateQuaternion:function(){void 0!==this._quaternion&&this._quaternion.setFromEuler(this,!1)},get x(){return this._x},set x(a){this._x=a,this._updateQuaternion()},get y(){return this._y},set y(a){this._y=a,this._updateQuaternion()},get z(){return this._z},set z(a){this._z=a,this._updateQuaternion()},get order(){return this._order},set order(a){this._order=a,this._updateQuaternion()},set:function(a,b,c,d){return this._x=a,this._y=b,this._z=c,this._order=d||this._order,this._updateQuaternion(),this},copy:function(a){return this._x=a._x,this._y=a._y,this._z=a._z,this._order=a._order,this._updateQuaternion(),this},setFromVector:function(a,b){return this._x=a.x,this._y=a.y,this._z=a.z,this._order=b||this._order,this._updateQuaternion(),this},setFromRotationMatrix:function(a,b){function c(a){return Math.min(Math.max(a,-1),1)}var d=a.elements,e=d[0],f=d[4],g=d[8],h=d[1],i=d[5],j=d[9],k=d[2],l=d[6],m=d[10]; -return b=b||this._order,"XYZ"===b?(this._y=Math.asin(c(g)),Math.abs(g)<.99999?(this._x=Math.atan2(-j,m),this._z=Math.atan2(-f,e)):(this._x=Math.atan2(l,i),this._z=0)):"YXZ"===b?(this._x=Math.asin(-c(j)),Math.abs(j)<.99999?(this._y=Math.atan2(g,m),this._z=Math.atan2(h,i)):(this._y=Math.atan2(-k,e),this._z=0)):"ZXY"===b?(this._x=Math.asin(c(l)),Math.abs(l)<.99999?(this._y=Math.atan2(-k,m),this._z=Math.atan2(-f,i)):(this._y=0,this._z=Math.atan2(h,e))):"ZYX"===b?(this._y=Math.asin(-c(k)),Math.abs(k)<.99999?(this._x=Math.atan2(l,m),this._z=Math.atan2(h,e)):(this._x=0,this._z=Math.atan2(-f,i))):"YZX"===b?(this._z=Math.asin(c(h)),Math.abs(h)<.99999?(this._x=Math.atan2(-j,i),this._y=Math.atan2(-k,e)):(this._x=0,this._y=Math.atan2(g,m))):"XZY"===b?(this._z=Math.asin(-c(f)),Math.abs(f)<.99999?(this._x=Math.atan2(l,i),this._y=Math.atan2(g,e)):(this._x=Math.atan2(-j,m),this._y=0)):console.warn("WARNING: Euler.setFromRotationMatrix() given unsupported order: "+b),this._order=b,this._updateQuaternion(),this},setFromQuaternion:function(a,b,c){function d(a){return Math.min(Math.max(a,-1),1)}var e=a.x*a.x,f=a.y*a.y,g=a.z*a.z,h=a.w*a.w;return b=b||this._order,"XYZ"===b?(this._x=Math.atan2(2*(a.x*a.w-a.y*a.z),h-e-f+g),this._y=Math.asin(d(2*(a.x*a.z+a.y*a.w))),this._z=Math.atan2(2*(a.z*a.w-a.x*a.y),h+e-f-g)):"YXZ"===b?(this._x=Math.asin(d(2*(a.x*a.w-a.y*a.z))),this._y=Math.atan2(2*(a.x*a.z+a.y*a.w),h-e-f+g),this._z=Math.atan2(2*(a.x*a.y+a.z*a.w),h-e+f-g)):"ZXY"===b?(this._x=Math.asin(d(2*(a.x*a.w+a.y*a.z))),this._y=Math.atan2(2*(a.y*a.w-a.z*a.x),h-e-f+g),this._z=Math.atan2(2*(a.z*a.w-a.x*a.y),h-e+f-g)):"ZYX"===b?(this._x=Math.atan2(2*(a.x*a.w+a.z*a.y),h-e-f+g),this._y=Math.asin(d(2*(a.y*a.w-a.x*a.z))),this._z=Math.atan2(2*(a.x*a.y+a.z*a.w),h+e-f-g)):"YZX"===b?(this._x=Math.atan2(2*(a.x*a.w-a.z*a.y),h-e+f-g),this._y=Math.atan2(2*(a.y*a.w-a.x*a.z),h+e-f-g),this._z=Math.asin(d(2*(a.x*a.y+a.z*a.w)))):"XZY"===b?(this._x=Math.atan2(2*(a.x*a.w+a.y*a.z),h-e+f-g),this._y=Math.atan2(2*(a.x*a.z+a.y*a.w),h+e-f-g),this._z=Math.asin(d(2*(a.z*a.w-a.x*a.y)))):console.warn("WARNING: Euler.setFromQuaternion() given unsupported order: "+b),this._order=b,c!==!1&&this._updateQuaternion(),this},reorder:function(){var a=new e.Quaternion;return function(b){a.setFromEuler(this),this.setFromQuaternion(a,b)}}(),fromArray:function(a){return this._x=a[0],this._y=a[1],this._z=a[2],void 0!==a[3]&&(this._order=a[3]),this._updateQuaternion(),this},toArray:function(){return[this._x,this._y,this._z,this._order]},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},clone:function(){return new e.Euler(this._x,this._y,this._z,this._order)}},e.Line3=function(a,b){this.start=void 0!==a?a:new e.Vector3,this.end=void 0!==b?b:new e.Vector3},e.Line3.prototype={constructor:e.Line3,set:function(a,b){return this.start.copy(a),this.end.copy(b),this},copy:function(a){return this.start.copy(a.start),this.end.copy(a.end),this},center:function(a){var b=a||new e.Vector3;return b.addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(a){var b=a||new e.Vector3;return b.subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(a,b){var c=b||new e.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new e.Vector3,b=new e.Vector3;return function(c,d){a.subVectors(c,this.start),b.subVectors(this.end,this.start);var f=b.dot(b),g=b.dot(a),h=g/f;return d&&(h=e.Math.clamp(h,0,1)),h}}(),closestPointToPoint:function(a,b,c){var d=this.closestPointToPointParameter(a,b),f=c||new e.Vector3;return this.delta(f).multiplyScalar(d).add(this.start)},applyMatrix4:function(a){return this.start.applyMatrix4(a),this.end.applyMatrix4(a),this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)},clone:function(){return(new e.Line3).copy(this)}},e.Box2=function(a,b){this.min=void 0!==a?a:new e.Vector2(1/0,1/0),this.max=void 0!==b?b:new e.Vector2(-1/0,-1/0)},e.Box2.prototype={constructor:e.Box2,set:function(a,b){return this.min.copy(a),this.max.copy(b),this},setFromPoints:function(a){if(a.length>0){var b=a[0];this.min.copy(b),this.max.copy(b);for(var c=1,d=a.length;d>c;c++)b=a[c],b.xthis.max.x&&(this.max.x=b.x),b.ythis.max.y&&(this.max.y=b.y)}else this.makeEmpty();return this},setFromCenterAndSize:function(){var a=new e.Vector2;return function(b,c){var d=a.copy(c).multiplyScalar(.5);return this.min.copy(b).sub(d),this.max.copy(b).add(d),this}}(),copy:function(a){return this.min.copy(a.min),this.max.copy(a.max),this},makeEmpty:function(){return this.min.x=this.min.y=1/0,this.max.x=this.max.y=-1/0,this},empty:function(){return this.max.xthis.max.x||a.ythis.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y?!0:!1},getParameter:function(a,b){var c=b||new e.Vector2;return c.set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y))},isIntersectionBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y?!1:!0},clampPoint:function(a,b){var c=b||new e.Vector2;return c.copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new e.Vector2;return function(b){var c=a.copy(b).clamp(this.min,this.max);return c.sub(b).length()}}(),intersect:function(a){return this.min.max(a.min),this.max.min(a.max),this},union:function(a){return this.min.min(a.min),this.max.max(a.max),this},translate:function(a){return this.min.add(a),this.max.add(a),this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new e.Box2).copy(this)}},e.Box3=function(a,b){this.min=void 0!==a?a:new e.Vector3(1/0,1/0,1/0),this.max=void 0!==b?b:new e.Vector3(-1/0,-1/0,-1/0)},e.Box3.prototype={constructor:e.Box3,set:function(a,b){return this.min.copy(a),this.max.copy(b),this},addPoint:function(a){a.xthis.max.x&&(this.max.x=a.x),a.ythis.max.y&&(this.max.y=a.y),a.zthis.max.z&&(this.max.z=a.z)},setFromPoints:function(a){if(a.length>0){var b=a[0];this.min.copy(b),this.max.copy(b);for(var c=1,d=a.length;d>c;c++)this.addPoint(a[c])}else this.makeEmpty();return this},setFromCenterAndSize:function(){var a=new e.Vector3;return function(b,c){var d=a.copy(c).multiplyScalar(.5);return this.min.copy(b).sub(d),this.max.copy(b).add(d),this}}(),setFromObject:function(){var a=new e.Vector3;return function(b){var c=this;return b.updateMatrixWorld(!0),this.makeEmpty(),b.traverse(function(b){if(void 0!==b.geometry&&void 0!==b.geometry.vertices)for(var d=b.geometry.vertices,e=0,f=d.length;f>e;e++)a.copy(d[e]),a.applyMatrix4(b.matrixWorld),c.expandByPoint(a)}),this}}(),copy:function(a){return this.min.copy(a.min),this.max.copy(a.max),this},makeEmpty:function(){return this.min.x=this.min.y=this.min.z=1/0,this.max.x=this.max.y=this.max.z=-1/0,this},empty:function(){return this.max.xthis.max.x||a.ythis.max.y||a.zthis.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z?!0:!1},getParameter:function(a,b){var c=b||new e.Vector3;return c.set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},isIntersectionBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y||a.max.zthis.max.z?!1:!0},clampPoint:function(a,b){var c=b||new e.Vector3;return c.copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new e.Vector3;return function(b){var c=a.copy(b).clamp(this.min,this.max);return c.sub(b).length()}}(),getBoundingSphere:function(){var a=new e.Vector3;return function(b){var c=b||new e.Sphere;return c.center=this.center(),c.radius=.5*this.size(a).length(),c}}(),intersect:function(a){return this.min.max(a.min),this.max.min(a.max),this},union:function(a){return this.min.min(a.min),this.max.max(a.max),this},applyMatrix4:function(){var a=[new e.Vector3,new e.Vector3,new e.Vector3,new e.Vector3,new e.Vector3,new e.Vector3,new e.Vector3,new e.Vector3];return function(b){return a[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(b),a[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(b),a[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(b),a[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(b),a[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(b),a[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(b),a[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(b),a[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(b),this.makeEmpty(),this.setFromPoints(a),this}}(),translate:function(a){return this.min.add(a),this.max.add(a),this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new e.Box3).copy(this)}},e.Matrix3=function(a,b,c,d,e,f,g,h,i){this.elements=new Float32Array(9),this.set(void 0!==a?a:1,b||0,c||0,d||0,void 0!==e?e:1,f||0,g||0,h||0,void 0!==i?i:1)},e.Matrix3.prototype={constructor:e.Matrix3,set:function(a,b,c,d,e,f,g,h,i){var j=this.elements;return j[0]=a,j[3]=b,j[6]=c,j[1]=d,j[4]=e,j[7]=f,j[2]=g,j[5]=h,j[8]=i,this},identity:function(){return this.set(1,0,0,0,1,0,0,0,1),this},copy:function(a){var b=a.elements;return this.set(b[0],b[3],b[6],b[1],b[4],b[7],b[2],b[5],b[8]),this},multiplyVector3:function(a){return console.warn("DEPRECATED: Matrix3's .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead."),a.applyMatrix3(this)},multiplyVector3Array:function(){var a=new e.Vector3;return function(b){for(var c=0,d=b.length;d>c;c+=3)a.x=b[c],a.y=b[c+1],a.z=b[c+2],a.applyMatrix3(this),b[c]=a.x,b[c+1]=a.y,b[c+2]=a.z;return b}}(),multiplyScalar:function(a){var b=this.elements;return b[0]*=a,b[3]*=a,b[6]*=a,b[1]*=a,b[4]*=a,b[7]*=a,b[2]*=a,b[5]*=a,b[8]*=a,this},determinant:function(){var a=this.elements,b=a[0],c=a[1],d=a[2],e=a[3],f=a[4],g=a[5],h=a[6],i=a[7],j=a[8];return b*f*j-b*g*i-c*e*j+c*g*h+d*e*i-d*f*h},getInverse:function(a,b){var c=a.elements,d=this.elements;d[0]=c[10]*c[5]-c[6]*c[9],d[1]=-c[10]*c[1]+c[2]*c[9],d[2]=c[6]*c[1]-c[2]*c[5],d[3]=-c[10]*c[4]+c[6]*c[8],d[4]=c[10]*c[0]-c[2]*c[8],d[5]=-c[6]*c[0]+c[2]*c[4],d[6]=c[9]*c[4]-c[5]*c[8],d[7]=-c[9]*c[0]+c[1]*c[8],d[8]=c[5]*c[0]-c[1]*c[4];var e=c[0]*d[0]+c[1]*d[3]+c[2]*d[6];if(0===e){var f="Matrix3.getInverse(): can't invert matrix, determinant is 0";if(b)throw new Error(f);return console.warn(f),this.identity(),this}return this.multiplyScalar(1/e),this},transpose:function(){var a,b=this.elements;return a=b[1],b[1]=b[3],b[3]=a,a=b[2],b[2]=b[6],b[6]=a,a=b[5],b[5]=b[7],b[7]=a,this},getNormalMatrix:function(a){return this.getInverse(a).transpose(),this},transposeIntoArray:function(a){var b=this.elements;return a[0]=b[0],a[1]=b[3],a[2]=b[6],a[3]=b[1],a[4]=b[4],a[5]=b[7],a[6]=b[2],a[7]=b[5],a[8]=b[8],this},fromArray:function(a){return this.elements.set(a),this},toArray:function(){var a=this.elements;return[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]]},clone:function(){var a=this.elements;return new e.Matrix3(a[0],a[3],a[6],a[1],a[4],a[7],a[2],a[5],a[8])}},e.Matrix4=function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p){this.elements=new Float32Array(16);var q=this.elements;q[0]=void 0!==a?a:1,q[4]=b||0,q[8]=c||0,q[12]=d||0,q[1]=e||0,q[5]=void 0!==f?f:1,q[9]=g||0,q[13]=h||0,q[2]=i||0,q[6]=j||0,q[10]=void 0!==k?k:1,q[14]=l||0,q[3]=m||0,q[7]=n||0,q[11]=o||0,q[15]=void 0!==p?p:1},e.Matrix4.prototype={constructor:e.Matrix4,set:function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p){var q=this.elements;return q[0]=a,q[4]=b,q[8]=c,q[12]=d,q[1]=e,q[5]=f,q[9]=g,q[13]=h,q[2]=i,q[6]=j,q[10]=k,q[14]=l,q[3]=m,q[7]=n,q[11]=o,q[15]=p,this},identity:function(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this},copy:function(a){return this.elements.set(a.elements),this},extractPosition:function(a){return console.warn("DEPRECATED: Matrix4's .extractPosition() has been renamed to .copyPosition()."),this.copyPosition(a)},copyPosition:function(a){var b=this.elements,c=a.elements;return b[12]=c[12],b[13]=c[13],b[14]=c[14],this},extractRotation:function(){var a=new e.Vector3;return function(b){var c=this.elements,d=b.elements,e=1/a.set(d[0],d[1],d[2]).length(),f=1/a.set(d[4],d[5],d[6]).length(),g=1/a.set(d[8],d[9],d[10]).length();return c[0]=d[0]*e,c[1]=d[1]*e,c[2]=d[2]*e,c[4]=d[4]*f,c[5]=d[5]*f,c[6]=d[6]*f,c[8]=d[8]*g,c[9]=d[9]*g,c[10]=d[10]*g,this}}(),makeRotationFromEuler:function(a){a instanceof e.Euler==!1&&console.error("ERROR: Matrix's .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.");var b=this.elements,c=a.x,d=a.y,f=a.z,g=Math.cos(c),h=Math.sin(c),i=Math.cos(d),j=Math.sin(d),k=Math.cos(f),l=Math.sin(f);if("XYZ"===a.order){var m=g*k,n=g*l,o=h*k,p=h*l;b[0]=i*k,b[4]=-i*l,b[8]=j,b[1]=n+o*j,b[5]=m-p*j,b[9]=-h*i,b[2]=p-m*j,b[6]=o+n*j,b[10]=g*i}else if("YXZ"===a.order){var q=i*k,r=i*l,s=j*k,t=j*l;b[0]=q+t*h,b[4]=s*h-r,b[8]=g*j,b[1]=g*l,b[5]=g*k,b[9]=-h,b[2]=r*h-s,b[6]=t+q*h,b[10]=g*i}else if("ZXY"===a.order){var q=i*k,r=i*l,s=j*k,t=j*l;b[0]=q-t*h,b[4]=-g*l,b[8]=s+r*h,b[1]=r+s*h,b[5]=g*k,b[9]=t-q*h,b[2]=-g*j,b[6]=h,b[10]=g*i}else if("ZYX"===a.order){var m=g*k,n=g*l,o=h*k,p=h*l;b[0]=i*k,b[4]=o*j-n,b[8]=m*j+p,b[1]=i*l,b[5]=p*j+m,b[9]=n*j-o,b[2]=-j,b[6]=h*i,b[10]=g*i}else if("YZX"===a.order){var u=g*i,v=g*j,w=h*i,x=h*j;b[0]=i*k,b[4]=x-u*l,b[8]=w*l+v,b[1]=l,b[5]=g*k,b[9]=-h*k,b[2]=-j*k,b[6]=v*l+w,b[10]=u-x*l}else if("XZY"===a.order){var u=g*i,v=g*j,w=h*i,x=h*j;b[0]=i*k,b[4]=-l,b[8]=j*k,b[1]=u*l+x,b[5]=g*k,b[9]=v*l-w,b[2]=w*l-v,b[6]=h*k,b[10]=x*l+u}return b[3]=0,b[7]=0,b[11]=0,b[12]=0,b[13]=0,b[14]=0,b[15]=1,this},setRotationFromQuaternion:function(a){return console.warn("DEPRECATED: Matrix4's .setRotationFromQuaternion() has been deprecated in favor of makeRotationFromQuaternion. Please update your code."),this.makeRotationFromQuaternion(a)},makeRotationFromQuaternion:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=a.w,g=c+c,h=d+d,i=e+e,j=c*g,k=c*h,l=c*i,m=d*h,n=d*i,o=e*i,p=f*g,q=f*h,r=f*i;return b[0]=1-(m+o),b[4]=k-r,b[8]=l+q,b[1]=k+r,b[5]=1-(j+o),b[9]=n-p,b[2]=l-q,b[6]=n+p,b[10]=1-(j+m),b[3]=0,b[7]=0,b[11]=0,b[12]=0,b[13]=0,b[14]=0,b[15]=1,this},lookAt:function(){var a=new e.Vector3,b=new e.Vector3,c=new e.Vector3;return function(d,e,f){var g=this.elements;return c.subVectors(d,e).normalize(),0===c.length()&&(c.z=1),a.crossVectors(f,c).normalize(),0===a.length()&&(c.x+=1e-4,a.crossVectors(f,c).normalize()),b.crossVectors(c,a),g[0]=a.x,g[4]=b.x,g[8]=c.x,g[1]=a.y,g[5]=b.y,g[9]=c.y,g[2]=a.z,g[6]=b.z,g[10]=c.z,this}}(),multiply:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Matrix4's .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(a,b)):this.multiplyMatrices(this,a)},multiplyMatrices:function(a,b){var c=a.elements,d=b.elements,e=this.elements,f=c[0],g=c[4],h=c[8],i=c[12],j=c[1],k=c[5],l=c[9],m=c[13],n=c[2],o=c[6],p=c[10],q=c[14],r=c[3],s=c[7],t=c[11],u=c[15],v=d[0],w=d[4],x=d[8],y=d[12],z=d[1],A=d[5],B=d[9],C=d[13],D=d[2],E=d[6],F=d[10],G=d[14],H=d[3],I=d[7],J=d[11],K=d[15];return e[0]=f*v+g*z+h*D+i*H,e[4]=f*w+g*A+h*E+i*I,e[8]=f*x+g*B+h*F+i*J,e[12]=f*y+g*C+h*G+i*K,e[1]=j*v+k*z+l*D+m*H,e[5]=j*w+k*A+l*E+m*I,e[9]=j*x+k*B+l*F+m*J,e[13]=j*y+k*C+l*G+m*K,e[2]=n*v+o*z+p*D+q*H,e[6]=n*w+o*A+p*E+q*I,e[10]=n*x+o*B+p*F+q*J,e[14]=n*y+o*C+p*G+q*K,e[3]=r*v+s*z+t*D+u*H,e[7]=r*w+s*A+t*E+u*I,e[11]=r*x+s*B+t*F+u*J,e[15]=r*y+s*C+t*G+u*K,this},multiplyToArray:function(a,b,c){var d=this.elements;return this.multiplyMatrices(a,b),c[0]=d[0],c[1]=d[1],c[2]=d[2],c[3]=d[3],c[4]=d[4],c[5]=d[5],c[6]=d[6],c[7]=d[7],c[8]=d[8],c[9]=d[9],c[10]=d[10],c[11]=d[11],c[12]=d[12],c[13]=d[13],c[14]=d[14],c[15]=d[15],this},multiplyScalar:function(a){var b=this.elements;return b[0]*=a,b[4]*=a,b[8]*=a,b[12]*=a,b[1]*=a,b[5]*=a,b[9]*=a,b[13]*=a,b[2]*=a,b[6]*=a,b[10]*=a,b[14]*=a,b[3]*=a,b[7]*=a,b[11]*=a,b[15]*=a,this},multiplyVector3:function(a){return console.warn("DEPRECATED: Matrix4's .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead."),a.applyProjection(this)},multiplyVector4:function(a){return console.warn("DEPRECATED: Matrix4's .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead."),a.applyMatrix4(this)},multiplyVector3Array:function(){var a=new e.Vector3;return function(b){for(var c=0,d=b.length;d>c;c+=3)a.x=b[c],a.y=b[c+1],a.z=b[c+2],a.applyProjection(this),b[c]=a.x,b[c+1]=a.y,b[c+2]=a.z;return b}}(),rotateAxis:function(a){console.warn("DEPRECATED: Matrix4's .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead."),a.transformDirection(this)},crossVector:function(a){return console.warn("DEPRECATED: Matrix4's .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead."),a.applyMatrix4(this)},determinant:function(){var a=this.elements,b=a[0],c=a[4],d=a[8],e=a[12],f=a[1],g=a[5],h=a[9],i=a[13],j=a[2],k=a[6],l=a[10],m=a[14],n=a[3],o=a[7],p=a[11],q=a[15];return n*(+e*h*k-d*i*k-e*g*l+c*i*l+d*g*m-c*h*m)+o*(+b*h*m-b*i*l+e*f*l-d*f*m+d*i*j-e*h*j)+p*(+b*i*k-b*g*m-e*f*k+c*f*m+e*g*j-c*i*j)+q*(-d*g*j-b*h*k+b*g*l+d*f*k-c*f*l+c*h*j)},transpose:function(){var a,b=this.elements;return a=b[1],b[1]=b[4],b[4]=a,a=b[2],b[2]=b[8],b[8]=a,a=b[6],b[6]=b[9],b[9]=a,a=b[3],b[3]=b[12],b[12]=a,a=b[7],b[7]=b[13],b[13]=a,a=b[11],b[11]=b[14],b[14]=a,this},flattenToArray:function(a){var b=this.elements;return a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[3],a[4]=b[4],a[5]=b[5],a[6]=b[6],a[7]=b[7],a[8]=b[8],a[9]=b[9],a[10]=b[10],a[11]=b[11],a[12]=b[12],a[13]=b[13],a[14]=b[14],a[15]=b[15],a},flattenToArrayOffset:function(a,b){var c=this.elements;return a[b]=c[0],a[b+1]=c[1],a[b+2]=c[2],a[b+3]=c[3],a[b+4]=c[4],a[b+5]=c[5],a[b+6]=c[6],a[b+7]=c[7],a[b+8]=c[8],a[b+9]=c[9],a[b+10]=c[10],a[b+11]=c[11],a[b+12]=c[12],a[b+13]=c[13],a[b+14]=c[14],a[b+15]=c[15],a},getPosition:function(){var a=new e.Vector3;return function(){console.warn("DEPRECATED: Matrix4's .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.");var b=this.elements;return a.set(b[12],b[13],b[14])}}(),setPosition:function(a){var b=this.elements;return b[12]=a.x,b[13]=a.y,b[14]=a.z,this},getInverse:function(a,b){var c=this.elements,d=a.elements,e=d[0],f=d[4],g=d[8],h=d[12],i=d[1],j=d[5],k=d[9],l=d[13],m=d[2],n=d[6],o=d[10],p=d[14],q=d[3],r=d[7],s=d[11],t=d[15];c[0]=k*p*r-l*o*r+l*n*s-j*p*s-k*n*t+j*o*t,c[4]=h*o*r-g*p*r-h*n*s+f*p*s+g*n*t-f*o*t,c[8]=g*l*r-h*k*r+h*j*s-f*l*s-g*j*t+f*k*t,c[12]=h*k*n-g*l*n-h*j*o+f*l*o+g*j*p-f*k*p,c[1]=l*o*q-k*p*q-l*m*s+i*p*s+k*m*t-i*o*t,c[5]=g*p*q-h*o*q+h*m*s-e*p*s-g*m*t+e*o*t,c[9]=h*k*q-g*l*q-h*i*s+e*l*s+g*i*t-e*k*t,c[13]=g*l*m-h*k*m+h*i*o-e*l*o-g*i*p+e*k*p,c[2]=j*p*q-l*n*q+l*m*r-i*p*r-j*m*t+i*n*t,c[6]=h*n*q-f*p*q-h*m*r+e*p*r+f*m*t-e*n*t,c[10]=f*l*q-h*j*q+h*i*r-e*l*r-f*i*t+e*j*t,c[14]=h*j*m-f*l*m-h*i*n+e*l*n+f*i*p-e*j*p,c[3]=k*n*q-j*o*q-k*m*r+i*o*r+j*m*s-i*n*s,c[7]=f*o*q-g*n*q+g*m*r-e*o*r-f*m*s+e*n*s,c[11]=g*j*q-f*k*q-g*i*r+e*k*r+f*i*s-e*j*s,c[15]=f*k*m-g*j*m+g*i*n-e*k*n-f*i*o+e*j*o;var u=e*c[0]+i*c[4]+m*c[8]+q*c[12];if(0==u){var v="Matrix4.getInverse(): can't invert matrix, determinant is 0";if(b)throw new Error(v);return console.warn(v),this.identity(),this}return this.multiplyScalar(1/u),this},translate:function(){console.warn("DEPRECATED: Matrix4's .translate() has been removed.")},rotateX:function(){console.warn("DEPRECATED: Matrix4's .rotateX() has been removed.")},rotateY:function(){console.warn("DEPRECATED: Matrix4's .rotateY() has been removed.")},rotateZ:function(){console.warn("DEPRECATED: Matrix4's .rotateZ() has been removed.")},rotateByAxis:function(){console.warn("DEPRECATED: Matrix4's .rotateByAxis() has been removed.")},scale:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z;return b[0]*=c,b[4]*=d,b[8]*=e,b[1]*=c,b[5]*=d,b[9]*=e,b[2]*=c,b[6]*=d,b[10]*=e,b[3]*=c,b[7]*=d,b[11]*=e,this},getMaxScaleOnAxis:function(){var a=this.elements,b=a[0]*a[0]+a[1]*a[1]+a[2]*a[2],c=a[4]*a[4]+a[5]*a[5]+a[6]*a[6],d=a[8]*a[8]+a[9]*a[9]+a[10]*a[10];return Math.sqrt(Math.max(b,Math.max(c,d)))},makeTranslation:function(a,b,c){return this.set(1,0,0,a,0,1,0,b,0,0,1,c,0,0,0,1),this},makeRotationX:function(a){var b=Math.cos(a),c=Math.sin(a);return this.set(1,0,0,0,0,b,-c,0,0,c,b,0,0,0,0,1),this},makeRotationY:function(a){var b=Math.cos(a),c=Math.sin(a);return this.set(b,0,c,0,0,1,0,0,-c,0,b,0,0,0,0,1),this},makeRotationZ:function(a){var b=Math.cos(a),c=Math.sin(a);return this.set(b,-c,0,0,c,b,0,0,0,0,1,0,0,0,0,1),this},makeRotationAxis:function(a,b){var c=Math.cos(b),d=Math.sin(b),e=1-c,f=a.x,g=a.y,h=a.z,i=e*f,j=e*g;return this.set(i*f+c,i*g-d*h,i*h+d*g,0,i*g+d*h,j*g+c,j*h-d*f,0,i*h-d*g,j*h+d*f,e*h*h+c,0,0,0,0,1),this},makeScale:function(a,b,c){return this.set(a,0,0,0,0,b,0,0,0,0,c,0,0,0,0,1),this},compose:function(a,b,c){return this.makeRotationFromQuaternion(b),this.scale(c),this.setPosition(a),this},decompose:function(){var a=new e.Vector3,b=new e.Matrix4;return function(c,d,e){var f=this.elements,g=a.set(f[0],f[1],f[2]).length(),h=a.set(f[4],f[5],f[6]).length(),i=a.set(f[8],f[9],f[10]).length(),j=this.determinant();0>j&&(g=-g),c.x=f[12],c.y=f[13],c.z=f[14],b.elements.set(this.elements);var k=1/g,l=1/h,m=1/i;return b.elements[0]*=k,b.elements[1]*=k,b.elements[2]*=k,b.elements[4]*=l,b.elements[5]*=l,b.elements[6]*=l,b.elements[8]*=m,b.elements[9]*=m,b.elements[10]*=m,d.setFromRotationMatrix(b),e.x=g,e.y=h,e.z=i,this}}(),makeFrustum:function(a,b,c,d,e,f){var g=this.elements,h=2*e/(b-a),i=2*e/(d-c),j=(b+a)/(b-a),k=(d+c)/(d-c),l=-(f+e)/(f-e),m=-2*f*e/(f-e);return g[0]=h,g[4]=0,g[8]=j,g[12]=0,g[1]=0,g[5]=i,g[9]=k,g[13]=0,g[2]=0,g[6]=0,g[10]=l,g[14]=m,g[3]=0,g[7]=0,g[11]=-1,g[15]=0,this},makePerspective:function(a,b,c,d){var f=c*Math.tan(e.Math.degToRad(.5*a)),g=-f,h=g*b,i=f*b;return this.makeFrustum(h,i,g,f,c,d)},makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,h=b-a,i=c-d,j=f-e,k=(b+a)/h,l=(c+d)/i,m=(f+e)/j;return g[0]=2/h,g[4]=0,g[8]=0,g[12]=-k,g[1]=0,g[5]=2/i,g[9]=0,g[13]=-l,g[2]=0,g[6]=0,g[10]=-2/j,g[14]=-m,g[3]=0,g[7]=0,g[11]=0,g[15]=1,this},fromArray:function(a){return this.elements.set(a),this},toArray:function(){var a=this.elements;return[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11],a[12],a[13],a[14],a[15]]},clone:function(){var a=this.elements;return new e.Matrix4(a[0],a[4],a[8],a[12],a[1],a[5],a[9],a[13],a[2],a[6],a[10],a[14],a[3],a[7],a[11],a[15])}},e.Ray=function(a,b){this.origin=void 0!==a?a:new e.Vector3,this.direction=void 0!==b?b:new e.Vector3},e.Ray.prototype={constructor:e.Ray,set:function(a,b){return this.origin.copy(a),this.direction.copy(b),this},copy:function(a){return this.origin.copy(a.origin),this.direction.copy(a.direction),this},at:function(a,b){var c=b||new e.Vector3;return c.copy(this.direction).multiplyScalar(a).add(this.origin)},recast:function(){var a=new e.Vector3;return function(b){return this.origin.copy(this.at(b,a)),this}}(),closestPointToPoint:function(a,b){var c=b||new e.Vector3;c.subVectors(a,this.origin);var d=c.dot(this.direction);return 0>d?c.copy(this.origin):c.copy(this.direction).multiplyScalar(d).add(this.origin)},distanceToPoint:function(){var a=new e.Vector3;return function(b){var c=a.subVectors(b,this.origin).dot(this.direction);return 0>c?this.origin.distanceTo(b):(a.copy(this.direction).multiplyScalar(c).add(this.origin),a.distanceTo(b))}}(),distanceSqToSegment:function(a,b,c,d){var e,f,g,h,i=a.clone().add(b).multiplyScalar(.5),j=b.clone().sub(a).normalize(),k=.5*a.distanceTo(b),l=this.origin.clone().sub(i),m=-this.direction.dot(j),n=l.dot(this.direction),o=-l.dot(j),p=l.lengthSq(),q=Math.abs(1-m*m);if(q>=0)if(e=m*o-n,f=m*n-o,h=k*q,e>=0)if(f>=-h)if(h>=f){var r=1/q;e*=r,f*=r,g=e*(e+m*f+2*n)+f*(m*e+f+2*o)+p}else f=k,e=Math.max(0,-(m*f+n)),g=-e*e+f*(f+2*o)+p;else f=-k,e=Math.max(0,-(m*f+n)),g=-e*e+f*(f+2*o)+p;else-h>=f?(e=Math.max(0,-(-m*k+n)),f=e>0?-k:Math.min(Math.max(-k,-o),k),g=-e*e+f*(f+2*o)+p):h>=f?(e=0,f=Math.min(Math.max(-k,-o),k),g=f*(f+2*o)+p):(e=Math.max(0,-(m*k+n)),f=e>0?k:Math.min(Math.max(-k,-o),k),g=-e*e+f*(f+2*o)+p);else f=m>0?-k:k,e=Math.max(0,-(m*f+n)),g=-e*e+f*(f+2*o)+p;return c&&c.copy(this.direction.clone().multiplyScalar(e).add(this.origin)),d&&d.copy(j.clone().multiplyScalar(f).add(i)),g},isIntersectionSphere:function(a){return this.distanceToPoint(a.center)<=a.radius},isIntersectionPlane:function(a){var b=a.distanceToPoint(this.origin);if(0===b)return!0;var c=a.normal.dot(this.direction);return 0>c*b?!0:!1},distanceToPlane:function(a){var b=a.normal.dot(this.direction);if(0==b)return 0==a.distanceToPoint(this.origin)?0:null;var c=-(this.origin.dot(a.normal)+a.constant)/b;return c>=0?c:null},intersectPlane:function(a,b){var c=this.distanceToPlane(a);return null===c?null:this.at(c,b)},isIntersectionBox:function(){var a=new e.Vector3;return function(b){return null!==this.intersectBox(b,a)}}(),intersectBox:function(a,b){var c,d,e,f,g,h,i=1/this.direction.x,j=1/this.direction.y,k=1/this.direction.z,l=this.origin;return i>=0?(c=(a.min.x-l.x)*i,d=(a.max.x-l.x)*i):(c=(a.max.x-l.x)*i,d=(a.min.x-l.x)*i),j>=0?(e=(a.min.y-l.y)*j,f=(a.max.y-l.y)*j):(e=(a.max.y-l.y)*j,f=(a.min.y-l.y)*j),c>f||e>d?null:((e>c||c!==c)&&(c=e),(d>f||d!==d)&&(d=f),k>=0?(g=(a.min.z-l.z)*k,h=(a.max.z-l.z)*k):(g=(a.max.z-l.z)*k,h=(a.min.z-l.z)*k),c>h||g>d?null:((g>c||c!==c)&&(c=g),(d>h||d!==d)&&(d=h),0>d?null:this.at(c>=0?c:d,b)))},intersectTriangle:function(){var a=new e.Vector3,b=new e.Vector3,c=new e.Vector3,d=new e.Vector3;return function(e,f,g,h,i){b.subVectors(f,e),c.subVectors(g,e),d.crossVectors(b,c);var j,k=this.direction.dot(d);if(k>0){if(h)return null;j=1}else{if(!(0>k))return null;j=-1,k=-k}a.subVectors(this.origin,e);var l=j*this.direction.dot(c.crossVectors(a,c));if(0>l)return null;var m=j*this.direction.dot(b.cross(a));if(0>m)return null;if(l+m>k)return null;var n=-j*a.dot(d);return 0>n?null:this.at(n/k,i)}}(),applyMatrix4:function(a){return this.direction.add(this.origin).applyMatrix4(a),this.origin.applyMatrix4(a),this.direction.sub(this.origin),this.direction.normalize(),this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)},clone:function(){return(new e.Ray).copy(this)}},e.Sphere=function(a,b){this.center=void 0!==a?a:new e.Vector3,this.radius=void 0!==b?b:0},e.Sphere.prototype={constructor:e.Sphere,set:function(a,b){return this.center.copy(a),this.radius=b,this},setFromPoints:function(){var a=new e.Box3;return function(b,c){var d=this.center;void 0!==c?d.copy(c):a.setFromPoints(b).center(d);for(var e=0,f=0,g=b.length;g>f;f++)e=Math.max(e,d.distanceToSquared(b[f]));return this.radius=Math.sqrt(e),this}}(),copy:function(a){return this.center.copy(a.center),this.radius=a.radius,this},empty:function(){return this.radius<=0},containsPoint:function(a){return a.distanceToSquared(this.center)<=this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},clampPoint:function(a,b){var c=this.center.distanceToSquared(a),d=b||new e.Vector3;return d.copy(a),c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this.radius).add(this.center)),d},getBoundingBox:function(a){var b=a||new e.Box3;return b.set(this.center,this.center),b.expandByScalar(this.radius),b},applyMatrix4:function(a){return this.center.applyMatrix4(a),this.radius=this.radius*a.getMaxScaleOnAxis(),this},translate:function(a){return this.center.add(a),this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new e.Sphere).copy(this)}},e.Frustum=function(a,b,c,d,f,g){this.planes=[void 0!==a?a:new e.Plane,void 0!==b?b:new e.Plane,void 0!==c?c:new e.Plane,void 0!==d?d:new e.Plane,void 0!==f?f:new e.Plane,void 0!==g?g:new e.Plane]},e.Frustum.prototype={constructor:e.Frustum,set:function(a,b,c,d,e,f){var g=this.planes;return g[0].copy(a),g[1].copy(b),g[2].copy(c),g[3].copy(d),g[4].copy(e),g[5].copy(f),this},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements,d=c[0],e=c[1],f=c[2],g=c[3],h=c[4],i=c[5],j=c[6],k=c[7],l=c[8],m=c[9],n=c[10],o=c[11],p=c[12],q=c[13],r=c[14],s=c[15];return b[0].setComponents(g-d,k-h,o-l,s-p).normalize(),b[1].setComponents(g+d,k+h,o+l,s+p).normalize(),b[2].setComponents(g+e,k+i,o+m,s+q).normalize(),b[3].setComponents(g-e,k-i,o-m,s-q).normalize(),b[4].setComponents(g-f,k-j,o-n,s-r).normalize(),b[5].setComponents(g+f,k+j,o+n,s+r).normalize(),this},intersectsObject:function(){var a=new e.Sphere;return function(b){var c=b.geometry;return null===c.boundingSphere&&c.computeBoundingSphere(),a.copy(c.boundingSphere),a.applyMatrix4(b.matrixWorld),this.intersectsSphere(a)}}(),intersectsSphere:function(a){for(var b=this.planes,c=a.center,d=-a.radius,e=0;6>e;e++){var f=b[e].distanceToPoint(c);if(d>f)return!1}return!0},intersectsBox:function(){var a=new e.Vector3,b=new e.Vector3;return function(c){for(var d=this.planes,e=0;6>e;e++){var f=d[e];a.x=f.normal.x>0?c.min.x:c.max.x,b.x=f.normal.x>0?c.max.x:c.min.x,a.y=f.normal.y>0?c.min.y:c.max.y,b.y=f.normal.y>0?c.max.y:c.min.y,a.z=f.normal.z>0?c.min.z:c.max.z,b.z=f.normal.z>0?c.max.z:c.min.z;var g=f.distanceToPoint(a),h=f.distanceToPoint(b);if(0>g&&0>h)return!1}return!0}}(),containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(b[c].distanceToPoint(a)<0)return!1;return!0},clone:function(){return(new e.Frustum).copy(this)}},e.Plane=function(a,b){this.normal=void 0!==a?a:new e.Vector3(1,0,0),this.constant=void 0!==b?b:0},e.Plane.prototype={constructor:e.Plane,set:function(a,b){return this.normal.copy(a),this.constant=b,this},setComponents:function(a,b,c,d){return this.normal.set(a,b,c),this.constant=d,this},setFromNormalAndCoplanarPoint:function(a,b){return this.normal.copy(a),this.constant=-b.dot(this.normal),this},setFromCoplanarPoints:function(){var a=new e.Vector3,b=new e.Vector3;return function(c,d,e){var f=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();return this.setFromNormalAndCoplanarPoint(f,c),this}}(),copy:function(a){return this.normal.copy(a.normal),this.constant=a.constant,this},normalize:function(){var a=1/this.normal.length();return this.normal.multiplyScalar(a),this.constant*=a,this},negate:function(){return this.constant*=-1,this.normal.negate(),this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){return this.orthoPoint(a,b).sub(a).negate()},orthoPoint:function(a,b){var c=this.distanceToPoint(a),d=b||new e.Vector3; -return d.copy(this.normal).multiplyScalar(c)},isIntersectionLine:function(a){var b=this.distanceToPoint(a.start),c=this.distanceToPoint(a.end);return 0>b&&c>0||0>c&&b>0},intersectLine:function(){var a=new e.Vector3;return function(b,c){var d=c||new e.Vector3,f=b.delta(a),g=this.normal.dot(f);if(0==g)return 0==this.distanceToPoint(b.start)?d.copy(b.start):void 0;var h=-(b.start.dot(this.normal)+this.constant)/g;return 0>h||h>1?void 0:d.copy(f).multiplyScalar(h).add(b.start)}}(),coplanarPoint:function(a){var b=a||new e.Vector3;return b.copy(this.normal).multiplyScalar(-this.constant)},applyMatrix4:function(){var a=new e.Vector3,b=new e.Vector3,c=new e.Matrix3;return function(d,e){var f=e||c.getNormalMatrix(d),g=a.copy(this.normal).applyMatrix3(f),h=this.coplanarPoint(b);return h.applyMatrix4(d),this.setFromNormalAndCoplanarPoint(g,h),this}}(),translate:function(a){return this.constant=this.constant-a.dot(this.normal),this},equals:function(a){return a.normal.equals(this.normal)&&a.constant==this.constant},clone:function(){return(new e.Plane).copy(this)}},e.Math={PI2:2*Math.PI,generateUUID:function(){var a,b="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),c=new Array(36),d=0;return function(){for(var e=0;36>e;e++)8==e||13==e||18==e||23==e?c[e]="-":14==e?c[e]="4":(2>=d&&(d=33554432+16777216*Math.random()|0),a=15&d,d>>=4,c[e]=b[19==e?3&a|8:a]);return c.join("")}}(),clamp:function(a,b,c){return b>a?b:a>c?c:a},clampBottom:function(a,b){return b>a?b:a},mapLinear:function(a,b,c,d,e){return d+(a-b)*(e-d)/(c-b)},smoothstep:function(a,b,c){return b>=a?0:a>=c?1:(a=(a-b)/(c-b),a*a*(3-2*a))},smootherstep:function(a,b,c){return b>=a?0:a>=c?1:(a=(a-b)/(c-b),a*a*a*(a*(6*a-15)+10))},random16:function(){return(65280*Math.random()+255*Math.random())/65535},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},sign:function(a){return 0>a?-1:a>0?1:0},degToRad:function(){var a=Math.PI/180;return function(b){return b*a}}(),radToDeg:function(){var a=180/Math.PI;return function(b){return b*a}}(),isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a}},e.Spline=function(a){function b(a,b,c,d,e,f,g){var h=.5*(c-a),i=.5*(d-b);return(2*(b-c)+h+i)*g+(-3*(b-c)-2*h-i)*f+h*e+b}this.points=a;var c,d,f,g,h,i,j,k,l,m=[],n={x:0,y:0,z:0};this.initFromArray=function(a){this.points=[];for(var b=0;bthis.points.length-2?this.points.length-1:d+1,m[3]=d>this.points.length-3?this.points.length-1:d+2,i=this.points[m[0]],j=this.points[m[1]],k=this.points[m[2]],l=this.points[m[3]],g=f*f,h=f*g,n.x=b(i.x,j.x,k.x,l.x,f,g,h),n.y=b(i.y,j.y,k.y,l.y,f,g,h),n.z=b(i.z,j.z,k.z,l.z,f,g,h),n},this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;c>a;a++)b=this.points[a],d[a]=[b.x,b.y,b.z];return d},this.getLength=function(a){var b,c,d,f,g=0,h=0,i=0,j=new e.Vector3,k=new e.Vector3,l=[],m=0;for(l[0]=0,a||(a=100),d=this.points.length*a,j.copy(this.points[0]),b=1;d>b;b++)c=b/d,f=this.getPoint(c),k.copy(f),m+=k.distanceTo(j),j.copy(f),g=(this.points.length-1)*c,h=Math.floor(g),h!=i&&(l[h]=m,i=h);return l[l.length]=m,{chunks:l,total:m}},this.reparametrizeByArcLength=function(a){var b,c,d,f,g,h,i,j,k=[],l=new e.Vector3,m=this.getLength();for(k.push(l.copy(this.points[0]).clone()),b=1;bc;c++)d=f+c*(1/i)*(g-f),j=this.getPoint(d),k.push(l.copy(j).clone());k.push(l.copy(this.points[b]).clone())}this.points=k}},e.Triangle=function(a,b,c){this.a=void 0!==a?a:new e.Vector3,this.b=void 0!==b?b:new e.Vector3,this.c=void 0!==c?c:new e.Vector3},e.Triangle.normal=function(){var a=new e.Vector3;return function(b,c,d,f){var g=f||new e.Vector3;g.subVectors(d,c),a.subVectors(b,c),g.cross(a);var h=g.lengthSq();return h>0?g.multiplyScalar(1/Math.sqrt(h)):g.set(0,0,0)}}(),e.Triangle.barycoordFromPoint=function(){var a=new e.Vector3,b=new e.Vector3,c=new e.Vector3;return function(d,f,g,h,i){a.subVectors(h,f),b.subVectors(g,f),c.subVectors(d,f);var j=a.dot(a),k=a.dot(b),l=a.dot(c),m=b.dot(b),n=b.dot(c),o=j*m-k*k,p=i||new e.Vector3;if(0==o)return p.set(-2,-1,-1);var q=1/o,r=(m*l-k*n)*q,s=(j*n-k*l)*q;return p.set(1-r-s,s,r)}}(),e.Triangle.containsPoint=function(){var a=new e.Vector3;return function(b,c,d,f){var g=e.Triangle.barycoordFromPoint(b,c,d,f,a);return g.x>=0&&g.y>=0&&g.x+g.y<=1}}(),e.Triangle.prototype={constructor:e.Triangle,set:function(a,b,c){return this.a.copy(a),this.b.copy(b),this.c.copy(c),this},setFromPointsAndIndices:function(a,b,c,d){return this.a.copy(a[b]),this.b.copy(a[c]),this.c.copy(a[d]),this},copy:function(a){return this.a.copy(a.a),this.b.copy(a.b),this.c.copy(a.c),this},area:function(){var a=new e.Vector3,b=new e.Vector3;return function(){return a.subVectors(this.c,this.b),b.subVectors(this.a,this.b),.5*a.cross(b).length()}}(),midpoint:function(a){var b=a||new e.Vector3;return b.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return e.Triangle.normal(this.a,this.b,this.c,a)},plane:function(a){var b=a||new e.Plane;return b.setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return e.Triangle.barycoordFromPoint(a,this.a,this.b,this.c,b)},containsPoint:function(a){return e.Triangle.containsPoint(a,this.a,this.b,this.c)},equals:function(a){return a.a.equals(this.a)&&a.b.equals(this.b)&&a.c.equals(this.c)},clone:function(){return(new e.Triangle).copy(this)}},e.Vertex=function(a){return console.warn("THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead."),a},e.UV=function(a,b){return console.warn("THREE.UV has been DEPRECATED. Use THREE.Vector2 instead."),new e.Vector2(a,b)},e.Clock=function(a){this.autoStart=void 0!==a?a:!0,this.startTime=0,this.oldTime=0,this.elapsedTime=0,this.running=!1},e.Clock.prototype={constructor:e.Clock,start:function(){this.startTime=void 0!==d.performance&&void 0!==d.performance.now?d.performance.now():Date.now(),this.oldTime=this.startTime,this.running=!0},stop:function(){this.getElapsedTime(),this.running=!1},getElapsedTime:function(){return this.getDelta(),this.elapsedTime},getDelta:function(){var a=0;if(this.autoStart&&!this.running&&this.start(),this.running){var b=void 0!==d.performance&&void 0!==d.performance.now?d.performance.now():Date.now();a=.001*(b-this.oldTime),this.oldTime=b,this.elapsedTime+=a}return a}},e.EventDispatcher=function(){},e.EventDispatcher.prototype={constructor:e.EventDispatcher,apply:function(a){a.addEventListener=e.EventDispatcher.prototype.addEventListener,a.hasEventListener=e.EventDispatcher.prototype.hasEventListener,a.removeEventListener=e.EventDispatcher.prototype.removeEventListener,a.dispatchEvent=e.EventDispatcher.prototype.dispatchEvent},addEventListener:function(a,b){void 0===this._listeners&&(this._listeners={});var c=this._listeners;void 0===c[a]&&(c[a]=[]),-1===c[a].indexOf(b)&&c[a].push(b)},hasEventListener:function(a,b){if(void 0===this._listeners)return!1;var c=this._listeners;return void 0!==c[a]&&-1!==c[a].indexOf(b)?!0:!1},removeEventListener:function(a,b){if(void 0!==this._listeners){var c=this._listeners,d=c[a];if(void 0!==d){var e=d.indexOf(b);-1!==e&&d.splice(e,1)}}},dispatchEvent:function(){var a=[];return function(b){if(void 0!==this._listeners){var c=this._listeners,d=c[b.type];if(void 0!==d){b.target=this;for(var e=d.length,f=0;e>f;f++)a[f]=d[f];for(var f=0;e>f;f++)a[f].call(this,b)}}}}()},function(a){a.Raycaster=function(b,c,d,e){this.ray=new a.Ray(b,c),this.near=d||0,this.far=e||1/0};var b=new a.Sphere,c=new a.Ray,d=(new a.Plane,new a.Vector3,new a.Vector3),e=new a.Matrix4,f=function(a,b){return a.distance-b.distance},g=new a.Vector3,h=new a.Vector3,i=new a.Vector3,j=function(f,k,l){if(f instanceof a.Sprite){d.setFromMatrixPosition(f.matrixWorld);var m=k.ray.distanceToPoint(d);if(m>f.scale.x)return l;l.push({distance:m,point:f.position,face:null,object:f})}else if(f instanceof a.LOD){d.setFromMatrixPosition(f.matrixWorld);var m=k.ray.origin.distanceTo(d);j(f.getObjectForDistance(m),k,l)}else if(f instanceof a.Mesh){var n=f.geometry;if(null===n.boundingSphere&&n.computeBoundingSphere(),b.copy(n.boundingSphere),b.applyMatrix4(f.matrixWorld),k.ray.isIntersectionSphere(b)===!1)return l;if(e.getInverse(f.matrixWorld),c.copy(k.ray).applyMatrix4(e),null!==n.boundingBox&&c.isIntersectionBox(n.boundingBox)===!1)return l;if(n instanceof a.BufferGeometry){var o=f.material;if(void 0===o)return l;var p,q,r,s=n.attributes,t=k.precision;if(void 0!==s.index)for(var u=n.offsets,v=s.index.array,w=s.position.array,x=0,y=u.length;y>x;++x)for(var z=u[x].start,A=u[x].count,B=u[x].index,C=z,D=z+A;D>C;C+=3){if(p=B+v[C],q=B+v[C+1],r=B+v[C+2],g.set(w[3*p],w[3*p+1],w[3*p+2]),h.set(w[3*q],w[3*q+1],w[3*q+2]),i.set(w[3*r],w[3*r+1],w[3*r+2]),o.side===a.BackSide)var E=c.intersectTriangle(i,h,g,!0);else var E=c.intersectTriangle(g,h,i,o.side!==a.DoubleSide);if(null!==E){E.applyMatrix4(f.matrixWorld);var m=k.ray.origin.distanceTo(E);t>m||mk.far||l.push({distance:m,point:E,indices:[p,q,r],face:null,faceIndex:null,object:f})}}else for(var u=n.offsets,w=s.position.array,C=0,D=s.position.array.length;D>C;C+=3){if(p=C,q=C+1,r=C+2,g.set(w[3*p],w[3*p+1],w[3*p+2]),h.set(w[3*q],w[3*q+1],w[3*q+2]),i.set(w[3*r],w[3*r+1],w[3*r+2]),o.side===a.BackSide)var E=c.intersectTriangle(i,h,g,!0);else var E=c.intersectTriangle(g,h,i,o.side!==a.DoubleSide);if(null!==E){E.applyMatrix4(f.matrixWorld);var m=k.ray.origin.distanceTo(E);t>m||mk.far||l.push({distance:m,point:E,indices:[p,q,r],face:null,faceIndex:null,object:f})}}}else if(n instanceof a.Geometry)for(var p,q,r,F=f.material instanceof a.MeshFaceMaterial,G=F===!0?f.material.materials:null,t=k.precision,H=n.vertices,I=0,J=n.faces.length;J>I;I++){var K=n.faces[I],o=F===!0?G[K.materialIndex]:f.material;if(void 0!==o){if(p=H[K.a],q=H[K.b],r=H[K.c],o.morphTargets===!0){var L=n.morphTargets,M=f.morphTargetInfluences;g.set(0,0,0),h.set(0,0,0),i.set(0,0,0);for(var N=0,O=L.length;O>N;N++){var P=M[N];if(0!==P){var Q=L[N].vertices;g.x+=(Q[K.a].x-p.x)*P,g.y+=(Q[K.a].y-p.y)*P,g.z+=(Q[K.a].z-p.z)*P,h.x+=(Q[K.b].x-q.x)*P,h.y+=(Q[K.b].y-q.y)*P,h.z+=(Q[K.b].z-q.z)*P,i.x+=(Q[K.c].x-r.x)*P,i.y+=(Q[K.c].y-r.y)*P,i.z+=(Q[K.c].z-r.z)*P}}g.add(p),h.add(q),i.add(r),p=g,q=h,r=i}if(o.side===a.BackSide)var E=c.intersectTriangle(r,q,p,!0);else var E=c.intersectTriangle(p,q,r,o.side!==a.DoubleSide);if(null!==E){E.applyMatrix4(f.matrixWorld);var m=k.ray.origin.distanceTo(E);t>m||mk.far||l.push({distance:m,point:E,face:K,faceIndex:I,object:f})}}}}else if(f instanceof a.Line){var t=k.linePrecision,R=t*t,n=f.geometry;if(null===n.boundingSphere&&n.computeBoundingSphere(),b.copy(n.boundingSphere),b.applyMatrix4(f.matrixWorld),k.ray.isIntersectionSphere(b)===!1)return l;if(e.getInverse(f.matrixWorld),c.copy(k.ray).applyMatrix4(e),n instanceof a.Geometry)for(var H=n.vertices,S=H.length,T=new a.Vector3,U=new a.Vector3,V=f.type===a.LineStrip?1:2,C=0;S-1>C;C+=V){var W=c.distanceSqToSegment(H[C],H[C+1],U,T);if(!(W>R)){var m=c.origin.distanceTo(U);mk.far||l.push({distance:m,point:T.clone().applyMatrix4(f.matrixWorld),face:null,faceIndex:null,object:f})}}}},k=function(a,b,c){for(var d=a.getDescendants(),e=0,f=d.length;f>e;e++)j(d[e],b,c)};a.Raycaster.prototype.precision=1e-4,a.Raycaster.prototype.linePrecision=1,a.Raycaster.prototype.set=function(a,b){this.ray.set(a,b)},a.Raycaster.prototype.intersectObject=function(a,b){var c=[];return b===!0&&k(a,this,c),j(a,this,c),c.sort(f),c},a.Raycaster.prototype.intersectObjects=function(a,b){for(var c=[],d=0,e=a.length;e>d;d++)j(a[d],this,c),b===!0&&k(a[d],this,c);return c.sort(f),c}}(e),e.Object3D=function(){this.id=e.Object3DIdCount++,this.uuid=e.Math.generateUUID(),this.name="",this.parent=void 0,this.children=[],this.up=new e.Vector3(0,1,0),this.position=new e.Vector3,this._rotation=new e.Euler,this._quaternion=new e.Quaternion,this.scale=new e.Vector3(1,1,1),this._rotation._quaternion=this.quaternion,this._quaternion._euler=this.rotation,this.renderDepth=null,this.rotationAutoUpdate=!0,this.matrix=new e.Matrix4,this.matrixWorld=new e.Matrix4,this.matrixAutoUpdate=!0,this.matrixWorldNeedsUpdate=!0,this.visible=!0,this.castShadow=!1,this.receiveShadow=!1,this.frustumCulled=!0,this.userData={}},e.Object3D.prototype={constructor:e.Object3D,get rotation(){return this._rotation},set rotation(a){this._rotation=a,this._rotation._quaternion=this._quaternion,this._quaternion._euler=this._rotation,this._rotation._updateQuaternion()},get quaternion(){return this._quaternion},set quaternion(a){this._quaternion=a,this._quaternion._euler=this._rotation,this._rotation._quaternion=this._quaternion,this._quaternion._updateEuler()},get eulerOrder(){return console.warn("DEPRECATED: Object3D's .eulerOrder has been moved to Object3D's .rotation.order."),this.rotation.order},set eulerOrder(a){console.warn("DEPRECATED: Object3D's .eulerOrder has been moved to Object3D's .rotation.order."),this.rotation.order=a},get useQuaternion(){console.warn("DEPRECATED: Object3D's .useQuaternion has been removed. The library now uses quaternions by default.")},set useQuaternion(a){console.warn("DEPRECATED: Object3D's .useQuaternion has been removed. The library now uses quaternions by default.")},applyMatrix:function(a){this.matrix.multiplyMatrices(a,this.matrix),this.matrix.decompose(this.position,this.quaternion,this.scale)},setRotationFromAxisAngle:function(a,b){this.quaternion.setFromAxisAngle(a,b)},setRotationFromEuler:function(a){this.quaternion.setFromEuler(a,!0)},setRotationFromMatrix:function(a){this.quaternion.setFromRotationMatrix(a)},setRotationFromQuaternion:function(a){this.quaternion.copy(a)},rotateOnAxis:function(){var a=new e.Quaternion;return function(b,c){return a.setFromAxisAngle(b,c),this.quaternion.multiply(a),this}}(),rotateX:function(){var a=new e.Vector3(1,0,0);return function(b){return this.rotateOnAxis(a,b)}}(),rotateY:function(){var a=new e.Vector3(0,1,0);return function(b){return this.rotateOnAxis(a,b)}}(),rotateZ:function(){var a=new e.Vector3(0,0,1);return function(b){return this.rotateOnAxis(a,b)}}(),translateOnAxis:function(){var a=new e.Vector3;return function(b,c){return a.copy(b),a.applyQuaternion(this.quaternion),this.position.add(a.multiplyScalar(c)),this}}(),translate:function(a,b){return console.warn("DEPRECATED: Object3D's .translate() has been removed. Use .translateOnAxis( axis, distance ) instead. Note args have been changed."),this.translateOnAxis(b,a)},translateX:function(){var a=new e.Vector3(1,0,0);return function(b){return this.translateOnAxis(a,b)}}(),translateY:function(){var a=new e.Vector3(0,1,0);return function(b){return this.translateOnAxis(a,b)}}(),translateZ:function(){var a=new e.Vector3(0,0,1);return function(b){return this.translateOnAxis(a,b)}}(),localToWorld:function(a){return a.applyMatrix4(this.matrixWorld)},worldToLocal:function(){var a=new e.Matrix4;return function(b){return b.applyMatrix4(a.getInverse(this.matrixWorld))}}(),lookAt:function(){var a=new e.Matrix4;return function(b){a.lookAt(b,this.position,this.up),this.quaternion.setFromRotationMatrix(a)}}(),add:function(a){if(a===this)return void console.warn("THREE.Object3D.add: An object can't be added as a child of itself.");if(a instanceof e.Object3D){void 0!==a.parent&&a.parent.remove(a),a.parent=this,a.dispatchEvent({type:"added"}),this.children.push(a);for(var b=this;void 0!==b.parent;)b=b.parent;void 0!==b&&b instanceof e.Scene&&b.__addObject(a)}},remove:function(a){var b=this.children.indexOf(a);if(-1!==b){a.parent=void 0,a.dispatchEvent({type:"removed"}),this.children.splice(b,1);for(var c=this;void 0!==c.parent;)c=c.parent;void 0!==c&&c instanceof e.Scene&&c.__removeObject(a)}},traverse:function(a){a(this);for(var b=0,c=this.children.length;c>b;b++)this.children[b].traverse(a)},getObjectById:function(a,b){for(var c=0,d=this.children.length;d>c;c++){var e=this.children[c];if(e.id===a)return e;if(b===!0&&(e=e.getObjectById(a,b),void 0!==e))return e}return void 0},getObjectByName:function(a,b){for(var c=0,d=this.children.length;d>c;c++){var e=this.children[c];if(e.name===a)return e;if(b===!0&&(e=e.getObjectByName(a,b),void 0!==e))return e}return void 0},getChildByName:function(a,b){return console.warn("DEPRECATED: Object3D's .getChildByName() has been renamed to .getObjectByName()."),this.getObjectByName(a,b)},getDescendants:function(a){void 0===a&&(a=[]),Array.prototype.push.apply(a,this.children);for(var b=0,c=this.children.length;c>b;b++)this.children[b].getDescendants(a);return a},updateMatrix:function(){this.matrix.compose(this.position,this.quaternion,this.scale),this.matrixWorldNeedsUpdate=!0},updateMatrixWorld:function(a){this.matrixAutoUpdate===!0&&this.updateMatrix(),(this.matrixWorldNeedsUpdate===!0||a===!0)&&(void 0===this.parent?this.matrixWorld.copy(this.matrix):this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix),this.matrixWorldNeedsUpdate=!1,a=!0);for(var b=0,c=this.children.length;c>b;b++)this.children[b].updateMatrixWorld(a)},clone:function(a,b){if(void 0===a&&(a=new e.Object3D),void 0===b&&(b=!0),a.name=this.name,a.up.copy(this.up),a.position.copy(this.position),a.quaternion.copy(this.quaternion),a.scale.copy(this.scale),a.renderDepth=this.renderDepth,a.rotationAutoUpdate=this.rotationAutoUpdate,a.matrix.copy(this.matrix),a.matrixWorld.copy(this.matrixWorld),a.matrixAutoUpdate=this.matrixAutoUpdate,a.matrixWorldNeedsUpdate=this.matrixWorldNeedsUpdate,a.visible=this.visible,a.castShadow=this.castShadow,a.receiveShadow=this.receiveShadow,a.frustumCulled=this.frustumCulled,a.userData=JSON.parse(JSON.stringify(this.userData)),b===!0)for(var c=0;c=0&&f>=0&&g>=0&&h>=0?!0:0>e&&0>f||0>g&&0>h?!1:(0>e?c=Math.max(c,e/(e-f)):0>f&&(d=Math.min(d,e/(e-f))),0>g?c=Math.max(c,g/(g-h)):0>h&&(d=Math.min(d,g/(g-h))),c>d?!1:(a.lerp(b,c),b.lerp(a,1-d),!0))}var i,j,k,l,m,n,o,p,q,r,s,t=[],u=0,v=[],w=0,x=[],y=0,z=[],A=0,B=[],C=0,D={objects:[],lights:[],elements:[]},E=new e.Vector3,F=new e.Vector3,G=new e.Vector3,H=new e.Vector3,I=new e.Vector4,J=new e.Box3(new e.Vector3(-1,-1,-1),new e.Vector3(1,1,1)),K=new e.Box3,L=new Array(3),M=(new Array(4),new e.Matrix4),N=new e.Matrix4,O=new e.Matrix4,P=new e.Matrix3,Q=new e.Frustum,R=new e.Vector4,S=new e.Vector4;this.projectVector=function(a,b){return b.matrixWorldInverse.getInverse(b.matrixWorld),N.multiplyMatrices(b.projectionMatrix,b.matrixWorldInverse),a.applyProjection(N)},this.unprojectVector=function(){var a=new e.Matrix4;return function(b,c){return a.getInverse(c.projectionMatrix),N.multiplyMatrices(c.matrixWorld,a),b.applyProjection(N)}}(),this.pickingRay=function(a,b){a.z=-1;var c=new e.Vector3(a.x,a.y,1);return this.unprojectVector(a,b),this.unprojectVector(c,b),c.sub(a).normalize(),new e.Raycaster(a,c)};var T=function(b){if(b.visible!==!1){b instanceof e.Light?D.lights.push(b):(b instanceof e.Mesh||b instanceof e.Line||b instanceof e.Sprite)&&(b.frustumCulled===!1||Q.intersectsObject(b)===!0)&&(i=a(),i.id=b.id,i.object=b,null!==b.renderDepth?i.z=b.renderDepth:(H.setFromMatrixPosition(b.matrixWorld),H.applyProjection(N),i.z=H.z),D.objects.push(i));for(var c=0,d=b.children.length;d>c;c++)T(b.children[c])}},U=function(a,b){j=0,D.objects.length=0,D.lights.length=0,T(a),b===!0&&D.objects.sort(g)},V=function(){var a=[],f=null,g=new e.Matrix3,h=function(b){f=b,g.getNormalMatrix(f.matrixWorld),a.length=0},i=function(a){var b=a.position,c=a.positionWorld,d=a.positionScreen;c.copy(b).applyMatrix4(s),d.copy(c).applyMatrix4(N);var e=1/d.w;d.x*=e,d.y*=e,d.z*=e,a.visible=d.x>=-1&&d.x<=1&&d.y>=-1&&d.y<=1&&d.z>=-1&&d.z<=1},j=function(a,c,d){k=b(),k.position.set(a,c,d),i(k)},l=function(b,c,d){a.push(b,c,d)},n=function(a,b,c){return L[0]=a.positionScreen,L[1]=b.positionScreen,L[2]=c.positionScreen,a.visible===!0||b.visible===!0||c.visible===!0||J.isIntersectionBox(K.setFromPoints(L))?(c.positionScreen.x-a.positionScreen.x)*(b.positionScreen.y-a.positionScreen.y)-(c.positionScreen.y-a.positionScreen.y)*(b.positionScreen.x-a.positionScreen.x)<0:!1},p=function(a,b){var c=v[a],e=v[b];o=d(),o.id=f.id,o.v1.copy(c),o.v2.copy(e),o.z=(c.positionScreen.z+e.positionScreen.z)/2,o.material=f.material,D.elements.push(o)},q=function(b,d,e){var h=v[b],i=v[d],j=v[e];if(n(h,i,j)===!0){m=c(),m.id=f.id,m.v1.copy(h),m.v2.copy(i),m.v3.copy(j),m.z=(h.positionScreen.z+i.positionScreen.z+j.positionScreen.z)/3;for(var k=0;3>k;k++){var l=3*arguments[k],o=m.vertexNormalsModel[k];o.set(a[l+0],a[l+1],a[l+2]),o.applyMatrix3(g).normalize()}m.vertexNormalsLength=3,m.material=f.material,D.elements.push(m)}};return{setObject:h,projectVertex:i,checkTriangleVisibility:n,pushVertex:j,pushNormal:l,pushLine:p,pushTriangle:q}},W=new V;this.projectScene=function(a,i,j,k){var t,u,w,x,y,z,A,B,C,H;n=0,p=0,r=0,D.elements.length=0,a.autoUpdate===!0&&a.updateMatrixWorld(),void 0===i.parent&&i.updateMatrixWorld(),M.copy(i.matrixWorldInverse.getInverse(i.matrixWorld)),N.multiplyMatrices(i.projectionMatrix,M),Q.setFromMatrix(N),U(a,j);for(var J=0,K=D.objects.length;K>J;J++)if(t=D.objects[J].object,u=t.geometry,W.setObject(t),s=t.matrixWorld,l=0,t instanceof e.Mesh){if(u instanceof e.BufferGeometry){var L=u.attributes,T=u.offsets;if(void 0===L.position)continue;for(var V=L.position.array,X=0,Y=V.length;Y>X;X+=3)W.pushVertex(V[X],V[X+1],V[X+2]);for(var Z=L.normal.array,X=0,Y=Z.length;Y>X;X+=3)W.pushNormal(Z[X],Z[X+1],Z[X+2]);if(void 0!==L.index){var $=L.index.array;if(T.length>0)for(var J=0;JX;X+=3)W.pushTriangle($[X]+ab,$[X+1]+ab,$[X+2]+ab);else for(var X=0,Y=$.length;Y>X;X+=3)W.pushTriangle($[X],$[X+1],$[X+2])}else for(var X=0,Y=V.length/3;Y>X;X+=3)W.pushTriangle(X,X+1,X+2)}else if(u instanceof e.Geometry){w=u.vertices,x=u.faces,A=u.faceVertexUvs,P.getNormalMatrix(s),C=t.material instanceof e.MeshFaceMaterial,H=C===!0?t.material:null;for(var bb=0,cb=w.length;cb>bb;bb++){var db=w[bb];W.pushVertex(db.x,db.y,db.z)}for(var eb=0,fb=x.length;fb>eb;eb++){y=x[eb];var gb=C===!0?H.materials[y.materialIndex]:t.material;if(void 0!==gb){var hb=gb.side,ib=v[y.a],jb=v[y.b],kb=v[y.c];if(gb.morphTargets===!0){var lb=u.morphTargets,mb=t.morphTargetInfluences,nb=ib.position,ob=jb.position,pb=kb.position;E.set(0,0,0),F.set(0,0,0),G.set(0,0,0);for(var qb=0,rb=lb.length;rb>qb;qb++){var sb=mb[qb];if(0!==sb){var tb=lb[qb].vertices;E.x+=(tb[y.a].x-nb.x)*sb,E.y+=(tb[y.a].y-nb.y)*sb,E.z+=(tb[y.a].z-nb.z)*sb,F.x+=(tb[y.b].x-ob.x)*sb,F.y+=(tb[y.b].y-ob.y)*sb,F.z+=(tb[y.b].z-ob.z)*sb,G.x+=(tb[y.c].x-pb.x)*sb,G.y+=(tb[y.c].y-pb.y)*sb,G.z+=(tb[y.c].z-pb.z)*sb}}ib.position.add(E),jb.position.add(F),kb.position.add(G),W.projectVertex(ib),W.projectVertex(jb),W.projectVertex(kb)}var ub=W.checkTriangleVisibility(ib,jb,kb);if(!(ub===!1&&hb===e.FrontSide||ub===!0&&hb===e.BackSide)){m=c(),m.id=t.id,m.v1.copy(ib),m.v2.copy(jb),m.v3.copy(kb),m.normalModel.copy(y.normal),ub!==!1||hb!==e.BackSide&&hb!==e.DoubleSide||m.normalModel.negate(),m.normalModel.applyMatrix3(P).normalize(),m.centroidModel.copy(y.centroid).applyMatrix4(s),z=y.vertexNormals;for(var vb=0,wb=Math.min(z.length,3);wb>vb;vb++){var xb=m.vertexNormalsModel[vb];xb.copy(z[vb]),ub!==!1||hb!==e.BackSide&&hb!==e.DoubleSide||xb.negate(),xb.applyMatrix3(P).normalize()}m.vertexNormalsLength=z.length;for(var yb=0,zb=Math.min(A.length,3);zb>yb;yb++)if(B=A[yb][eb],void 0!==B)for(var Ab=0,Bb=B.length;Bb>Ab;Ab++)m.uvs[yb][Ab]=B[Ab];m.color=y.color,m.material=gb,m.z=(ib.positionScreen.z+jb.positionScreen.z+kb.positionScreen.z)/3,D.elements.push(m)}}}}}else if(t instanceof e.Line){if(u instanceof e.BufferGeometry){var L=u.attributes;if(void 0!==L.position){for(var V=L.position.array,X=0,Y=V.length;Y>X;X+=3)W.pushVertex(V[X],V[X+1],V[X+2]);if(void 0!==L.index)for(var $=L.index.array,X=0,Y=$.length;Y>X;X+=2)W.pushLine($[X],$[X+1]);else for(var X=0,Y=V.length/3-1;Y>X;X++)W.pushLine(X,X+1)}}else if(u instanceof e.Geometry){if(O.multiplyMatrices(N,s),w=t.geometry.vertices,0===w.length)continue;ib=b(),ib.positionScreen.copy(w[0]).applyMatrix4(O);for(var Cb=t.type===e.LinePieces?2:1,bb=1,cb=w.length;cb>bb;bb++)ib=b(),ib.positionScreen.copy(w[bb]).applyMatrix4(O),(bb+1)%Cb>0||(jb=v[l-2],R.copy(ib.positionScreen),S.copy(jb.positionScreen),h(R,S)===!0&&(R.multiplyScalar(1/R.w),S.multiplyScalar(1/S.w),o=d(),o.id=t.id,o.v1.positionScreen.copy(R),o.v2.positionScreen.copy(S),o.z=Math.max(R.z,S.z),o.material=t.material,t.material.vertexColors===e.VertexColors&&(o.vertexColors[0].copy(t.geometry.colors[bb]),o.vertexColors[1].copy(t.geometry.colors[bb-1])),D.elements.push(o)))}}else if(t instanceof e.Sprite){I.set(s.elements[12],s.elements[13],s.elements[14],1),I.applyMatrix4(N);var Db=1/I.w;I.z*=Db,I.z>=-1&&I.z<=1&&(q=f(),q.id=t.id,q.x=I.x*Db,q.y=I.y*Db,q.z=I.z,q.object=t,q.rotation=t.rotation,q.scale.x=t.scale.x*Math.abs(q.x-(I.x+i.projectionMatrix.elements[0])/(I.w+i.projectionMatrix.elements[12])),q.scale.y=t.scale.y*Math.abs(q.y-(I.y+i.projectionMatrix.elements[5])/(I.w+i.projectionMatrix.elements[13])),q.material=t.material,D.elements.push(q))}return k===!0&&D.elements.sort(g),D}},e.Face3=function(a,b,c,d,f,g){this.a=a,this.b=b,this.c=c,this.normal=d instanceof e.Vector3?d:new e.Vector3,this.vertexNormals=d instanceof Array?d:[],this.color=f instanceof e.Color?f:new e.Color,this.vertexColors=f instanceof Array?f:[],this.vertexTangents=[],this.materialIndex=void 0!==g?g:0,this.centroid=new e.Vector3},e.Face3.prototype={constructor:e.Face3,clone:function(){var a=new e.Face3(this.a,this.b,this.c);a.normal.copy(this.normal),a.color.copy(this.color),a.centroid.copy(this.centroid),a.materialIndex=this.materialIndex;var b,c;for(b=0,c=this.vertexNormals.length;c>b;b++)a.vertexNormals[b]=this.vertexNormals[b].clone();for(b=0,c=this.vertexColors.length;c>b;b++)a.vertexColors[b]=this.vertexColors[b].clone();for(b=0,c=this.vertexTangents.length;c>b;b++)a.vertexTangents[b]=this.vertexTangents[b].clone();return a}},e.Face4=function(a,b,c,d,f,g,h){return console.warn("THREE.Face4 has been removed. A THREE.Face3 will be created instead."),new e.Face3(a,b,c,f,g,h)},e.BufferGeometry=function(){this.id=e.GeometryIdCount++,this.uuid=e.Math.generateUUID(),this.name="",this.attributes={},this.offsets=[],this.boundingBox=null,this.boundingSphere=null},e.BufferGeometry.prototype={constructor:e.BufferGeometry,addAttribute:function(a,b,c,d){return this.attributes[a]={array:new b(c*d),itemSize:d},this.attributes[a]},applyMatrix:function(a){var b=this.attributes.position;void 0!==b&&(a.multiplyVector3Array(b.array),b.needsUpdate=!0);var c=this.attributes.normal;if(void 0!==c){var d=(new e.Matrix3).getNormalMatrix(a);d.multiplyVector3Array(c.array),c.needsUpdate=!0}},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new e.Box3);var a=this.attributes.position.array;if(a){var b=this.boundingBox;a.length>=3&&(b.min.x=b.max.x=a[0],b.min.y=b.max.y=a[1],b.min.z=b.max.z=a[2]);for(var c=3,d=a.length;d>c;c+=3){var f=a[c],g=a[c+1],h=a[c+2];fb.max.x&&(b.max.x=f),gb.max.y&&(b.max.y=g),hb.max.z&&(b.max.z=h)}}(void 0===a||0===a.length)&&(this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0))},computeBoundingSphere:function(){var a=new e.Box3,b=new e.Vector3;return function(){null===this.boundingSphere&&(this.boundingSphere=new e.Sphere);var c=this.attributes.position.array;if(c){a.makeEmpty();for(var d=this.boundingSphere.center,f=0,g=c.length;g>f;f+=3)b.set(c[f],c[f+1],c[f+2]),a.addPoint(b);a.center(d);for(var h=0,f=0,g=c.length;g>f;f+=3)b.set(c[f],c[f+1],c[f+2]),h=Math.max(h,d.distanceToSquared(b));this.boundingSphere.radius=Math.sqrt(h)}}}(),computeVertexNormals:function(){if(this.attributes.position){var a,b,c,d,f=this.attributes.position.array.length;if(void 0===this.attributes.normal)this.attributes.normal={itemSize:3,array:new Float32Array(f)};else for(a=0,b=this.attributes.normal.array.length;b>a;a++)this.attributes.normal.array[a]=0;var g,h,i,j,k,l,m=this.attributes.position.array,n=this.attributes.normal.array,o=new e.Vector3,p=new e.Vector3,q=new e.Vector3,r=new e.Vector3,s=new e.Vector3;if(this.attributes.index){var t=this.attributes.index.array,u=this.offsets;for(c=0,d=u.length;d>c;++c){var v=u[c].start,w=u[c].count,x=u[c].index;for(a=v,b=v+w;b>a;a+=3)g=x+t[a],h=x+t[a+1],i=x+t[a+2],j=m[3*g],k=m[3*g+1],l=m[3*g+2],o.set(j,k,l),j=m[3*h],k=m[3*h+1],l=m[3*h+2],p.set(j,k,l),j=m[3*i],k=m[3*i+1],l=m[3*i+2],q.set(j,k,l),r.subVectors(q,p),s.subVectors(o,p),r.cross(s),n[3*g]+=r.x,n[3*g+1]+=r.y,n[3*g+2]+=r.z,n[3*h]+=r.x,n[3*h+1]+=r.y,n[3*h+2]+=r.z,n[3*i]+=r.x,n[3*i+1]+=r.y,n[3*i+2]+=r.z}}else for(a=0,b=m.length;b>a;a+=9)j=m[a],k=m[a+1],l=m[a+2],o.set(j,k,l),j=m[a+3],k=m[a+4],l=m[a+5],p.set(j,k,l),j=m[a+6],k=m[a+7],l=m[a+8],q.set(j,k,l),r.subVectors(q,p),s.subVectors(o,p),r.cross(s),n[a]=r.x,n[a+1]=r.y,n[a+2]=r.z,n[a+3]=r.x,n[a+4]=r.y,n[a+5]=r.z,n[a+6]=r.x,n[a+7]=r.y,n[a+8]=r.z;this.normalizeNormals(),this.normalsNeedUpdate=!0}},normalizeNormals:function(){for(var a,b,c,d,e=this.attributes.normal.array,f=0,g=e.length;g>f;f+=3)a=e[f],b=e[f+1],c=e[f+2],d=1/Math.sqrt(a*a+b*b+c*c),e[f]*=d,e[f+1]*=d,e[f+2]*=d},computeTangents:function(){function a(a,b,c){n=d[3*a],o=d[3*a+1],p=d[3*a+2],q=d[3*b],r=d[3*b+1],s=d[3*b+2],t=d[3*c],u=d[3*c+1],v=d[3*c+2],w=g[2*a],x=g[2*a+1],y=g[2*b],z=g[2*b+1],A=g[2*c],B=g[2*c+1],C=q-n,D=t-n,E=r-o,F=u-o,G=s-p,H=v-p,I=y-w,J=A-w,K=z-x,L=B-x,M=1/(I*L-J*K),U.set((L*C-K*D)*M,(L*E-K*F)*M,(L*G-K*H)*M),V.set((I*D-J*C)*M,(I*F-J*E)*M,(I*H-J*G)*M),k[a].add(U),k[b].add(U),k[c].add(U),l[a].add(V),l[b].add(V),l[c].add(V)}function b(a){db.x=f[3*a],db.y=f[3*a+1],db.z=f[3*a+2],eb.copy(db),_=k[a],bb.copy(_),bb.sub(db.multiplyScalar(db.dot(_))).normalize(),cb.crossVectors(eb,_),ab=cb.dot(l[a]),$=0>ab?-1:1,j[4*a]=bb.x,j[4*a+1]=bb.y,j[4*a+2]=bb.z,j[4*a+3]=$}if(void 0===this.attributes.index||void 0===this.attributes.position||void 0===this.attributes.normal||void 0===this.attributes.uv)return void console.warn("Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");var c=this.attributes.index.array,d=this.attributes.position.array,f=this.attributes.normal.array,g=this.attributes.uv.array,h=d.length/3;if(void 0===this.attributes.tangent){var i=4*h;this.attributes.tangent={itemSize:4,array:new Float32Array(i)}}for(var j=this.attributes.tangent.array,k=[],l=[],m=0;h>m;m++)k[m]=new e.Vector3,l[m]=new e.Vector3;var n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U=new e.Vector3,V=new e.Vector3,W=this.offsets;for(P=0,Q=W.length;Q>P;++P){var X=W[P].start,Y=W[P].count,Z=W[P].index;for(N=X,O=X+Y;O>N;N+=3)R=Z+c[N],S=Z+c[N+1],T=Z+c[N+2],a(R,S,T)}var $,_,ab,bb=new e.Vector3,cb=new e.Vector3,db=new e.Vector3,eb=new e.Vector3;for(P=0,Q=W.length;Q>P;++P){var X=W[P].start,Y=W[P].count,Z=W[P].index;for(N=X,O=X+Y;O>N;N+=3)R=Z+c[N],S=Z+c[N+1],T=Z+c[N+2],b(R),b(S),b(T)}},computeOffsets:function(a){var b=a;void 0===a&&(b=65535);for(var c=(Date.now(),this.attributes.index.array),d=this.attributes.position.array,e=(d.length/3,c.length/3),f=new Uint16Array(c.length),g=0,h=0,i=[{start:0,count:0,index:0}],j=i[0],k=0,l=0,m=new Int32Array(6),n=new Int32Array(d.length),o=new Int32Array(d.length),p=0;pq;q++){l=0;for(var r=0;3>r;r++){var s=c[3*q+r];-1==n[s]?(m[2*r]=s,m[2*r+1]=-1,l++):n[s]j.index+b){var u={start:g,count:0,index:h};i.push(u),j=u;for(var v=0;6>v;v+=2){var w=m[v+1];w>-1&&wv;v+=2){var s=m[v],w=m[v+1];-1===w&&(w=h++),n[s]=w,o[w]=s,f[g++]=w-j.index,j.count++}}return this.reorderBuffers(f,o,h),this.offsets=i,i},reorderBuffers:function(a,b,c){var d={},e=[Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];for(var f in this.attributes)if("index"!=f)for(var g=this.attributes[f].array,h=0,i=e.length;i>h;h++){var j=e[h];if(g instanceof j){d[f]=new j(this.attributes[f].itemSize*c);break}}for(var k=0;c>k;k++){var l=b[k];for(var f in this.attributes)if("index"!=f)for(var m=this.attributes[f].array,n=this.attributes[f].itemSize,o=d[f],p=0;n>p;p++)o[k*n+p]=m[l*n+p]}this.attributes.index.array=a;for(var f in this.attributes)"index"!=f&&(this.attributes[f].array=d[f],this.attributes[f].numItems=this.attributes[f].itemSize*c)},clone:function(){var a=new e.BufferGeometry,b=[Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];for(var c in this.attributes){for(var d=this.attributes[c],f=d.array,g={itemSize:d.itemSize,array:null},h=0,i=b.length;i>h;h++){var j=b[h];if(f instanceof j){g.array=new j(f);break}}a.attributes[c]=g}for(var h=0,i=this.offsets.length;i>h;h++){var k=this.offsets[h];a.offsets.push({start:k.start,index:k.index,count:k.count})}return a},dispose:function(){this.dispatchEvent({type:"dispose"})}},e.EventDispatcher.prototype.apply(e.BufferGeometry.prototype),e.Geometry=function(){this.id=e.GeometryIdCount++,this.uuid=e.Math.generateUUID(),this.name="",this.vertices=[],this.colors=[],this.faces=[],this.faceVertexUvs=[[]],this.morphTargets=[],this.morphColors=[],this.morphNormals=[],this.skinWeights=[],this.skinIndices=[],this.lineDistances=[],this.boundingBox=null,this.boundingSphere=null,this.hasTangents=!1,this.dynamic=!0,this.verticesNeedUpdate=!1,this.elementsNeedUpdate=!1,this.uvsNeedUpdate=!1,this.normalsNeedUpdate=!1,this.tangentsNeedUpdate=!1,this.colorsNeedUpdate=!1,this.lineDistancesNeedUpdate=!1,this.buffersNeedUpdate=!1},e.Geometry.prototype={constructor:e.Geometry,applyMatrix:function(a){for(var b=(new e.Matrix3).getNormalMatrix(a),c=0,d=this.vertices.length;d>c;c++){var f=this.vertices[c];f.applyMatrix4(a)}for(var c=0,d=this.faces.length;d>c;c++){var g=this.faces[c];g.normal.applyMatrix3(b).normalize();for(var h=0,i=g.vertexNormals.length;i>h;h++)g.vertexNormals[h].applyMatrix3(b).normalize();g.centroid.applyMatrix4(a)}this.boundingBox instanceof e.Box3&&this.computeBoundingBox(),this.boundingSphere instanceof e.Sphere&&this.computeBoundingSphere()},computeCentroids:function(){var a,b,c;for(a=0,b=this.faces.length;b>a;a++)c=this.faces[a],c.centroid.set(0,0,0),c.centroid.add(this.vertices[c.a]),c.centroid.add(this.vertices[c.b]),c.centroid.add(this.vertices[c.c]),c.centroid.divideScalar(3)},computeFaceNormals:function(){for(var a=new e.Vector3,b=new e.Vector3,c=0,d=this.faces.length;d>c;c++){var f=this.faces[c],g=this.vertices[f.a],h=this.vertices[f.b],i=this.vertices[f.c];a.subVectors(i,h),b.subVectors(g,h),a.cross(b),a.normalize(),f.normal.copy(a)}},computeVertexNormals:function(a){var b,c,d,f,g,h;for(h=new Array(this.vertices.length),b=0,c=this.vertices.length;c>b;b++)h[b]=new e.Vector3;if(a){{var i,j,k,l=new e.Vector3,m=new e.Vector3;new e.Vector3,new e.Vector3,new e.Vector3}for(d=0,f=this.faces.length;f>d;d++)g=this.faces[d],i=this.vertices[g.a],j=this.vertices[g.b],k=this.vertices[g.c],l.subVectors(k,j),m.subVectors(i,j),l.cross(m),h[g.a].add(l),h[g.b].add(l),h[g.c].add(l)}else for(d=0,f=this.faces.length;f>d;d++)g=this.faces[d],h[g.a].add(g.normal),h[g.b].add(g.normal),h[g.c].add(g.normal);for(b=0,c=this.vertices.length;c>b;b++)h[b].normalize();for(d=0,f=this.faces.length;f>d;d++)g=this.faces[d],g.vertexNormals[0]=h[g.a].clone(),g.vertexNormals[1]=h[g.b].clone(),g.vertexNormals[2]=h[g.c].clone()},computeMorphNormals:function(){var a,b,c,d,f;for(c=0,d=this.faces.length;d>c;c++)for(f=this.faces[c],f.__originalFaceNormal?f.__originalFaceNormal.copy(f.normal):f.__originalFaceNormal=f.normal.clone(),f.__originalVertexNormals||(f.__originalVertexNormals=[]),a=0,b=f.vertexNormals.length;b>a;a++)f.__originalVertexNormals[a]?f.__originalVertexNormals[a].copy(f.vertexNormals[a]):f.__originalVertexNormals[a]=f.vertexNormals[a].clone();var g=new e.Geometry;for(g.faces=this.faces,a=0,b=this.morphTargets.length;b>a;a++){if(!this.morphNormals[a]){this.morphNormals[a]={},this.morphNormals[a].faceNormals=[],this.morphNormals[a].vertexNormals=[];var h,i,j=this.morphNormals[a].faceNormals,k=this.morphNormals[a].vertexNormals;for(c=0,d=this.faces.length;d>c;c++)f=this.faces[c],h=new e.Vector3,i={a:new e.Vector3,b:new e.Vector3,c:new e.Vector3},j.push(h),k.push(i)}var l=this.morphNormals[a];g.vertices=this.morphTargets[a].vertices,g.computeFaceNormals(),g.computeVertexNormals();var h,i;for(c=0,d=this.faces.length;d>c;c++)f=this.faces[c],h=l.faceNormals[c],i=l.vertexNormals[c],h.copy(f.normal),i.a.copy(f.vertexNormals[0]),i.b.copy(f.vertexNormals[1]),i.c.copy(f.vertexNormals[2])}for(c=0,d=this.faces.length;d>c;c++)f=this.faces[c],f.normal=f.__originalFaceNormal,f.vertexNormals=f.__originalVertexNormals},computeTangents:function(){function a(a,b,c,d,e,f,g){k=a.vertices[b],l=a.vertices[c],m=a.vertices[d],n=j[e],o=j[f],p=j[g],q=l.x-k.x,r=m.x-k.x,s=l.y-k.y,t=m.y-k.y,u=l.z-k.z,v=m.z-k.z,w=o.x-n.x,x=p.x-n.x,y=o.y-n.y,z=p.y-n.y,A=1/(w*z-x*y),G.set((z*q-y*r)*A,(z*s-y*t)*A,(z*u-y*v)*A),H.set((w*r-x*q)*A,(w*t-x*s)*A,(w*v-x*u)*A),E[b].add(G),E[c].add(G),E[d].add(G),F[b].add(H),F[c].add(H),F[d].add(H)}var b,c,d,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E=[],F=[],G=new e.Vector3,H=new e.Vector3,I=new e.Vector3,J=new e.Vector3,K=new e.Vector3;for(d=0,f=this.vertices.length;f>d;d++)E[d]=new e.Vector3,F[d]=new e.Vector3;for(b=0,c=this.faces.length;c>b;b++)i=this.faces[b],j=this.faceVertexUvs[0][b],a(this,i.a,i.b,i.c,0,1,2);var L=["a","b","c","d"];for(b=0,c=this.faces.length;c>b;b++)for(i=this.faces[b],g=0;gC?-1:1,i.vertexTangents[g]=new e.Vector4(I.x,I.y,I.z,D);this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;d>c;c++)c>0&&(a+=b[c].distanceTo(b[c-1])),this.lineDistances[c]=a},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new e.Box3),this.boundingBox.setFromPoints(this.vertices)},computeBoundingSphere:function(){null===this.boundingSphere&&(this.boundingSphere=new e.Sphere),this.boundingSphere.setFromPoints(this.vertices)},mergeVertices:function(){var a,b,c,d,e,f,g,h,i={},j=[],k=[],l=4,m=Math.pow(10,l);for(c=0,d=this.vertices.length;d>c;c++)a=this.vertices[c],b=Math.round(a.x*m)+"_"+Math.round(a.y*m)+"_"+Math.round(a.z*m),void 0===i[b]?(i[b]=c,j.push(this.vertices[c]),k[c]=j.length-1):k[c]=k[i[b]];var n=[];for(c=0,d=this.faces.length;d>c;c++){e=this.faces[c],e.a=k[e.a],e.b=k[e.b],e.c=k[e.c],f=[e.a,e.b,e.c];for(var o=-1,p=0;3>p;p++)if(f[p]==f[(p+1)%3]){o=p,n.push(c);break}}for(c=n.length-1;c>=0;c--){var q=n[c];for(this.faces.splice(q,1),g=0,h=this.faceVertexUvs.length;h>g;g++)this.faceVertexUvs[g].splice(q,1)}var r=this.vertices.length-j.length;return this.vertices=j,r},makeGroups:function(){var a=0;return function(b){var c,d,e,f,g,h={},i=this.morphTargets.length,j=this.morphNormals.length;for(this.geometryGroups={},c=0,d=this.faces.length;d>c;c++)e=this.faces[c],f=b?e.materialIndex:0,f in h||(h[f]={hash:f,counter:0}),g=h[f].hash+"_"+h[f].counter,g in this.geometryGroups||(this.geometryGroups[g]={faces3:[],materialIndex:f,vertices:0,numMorphTargets:i,numMorphNormals:j}),this.geometryGroups[g].vertices+3>65535&&(h[f].counter+=1,g=h[f].hash+"_"+h[f].counter,g in this.geometryGroups||(this.geometryGroups[g]={faces3:[],materialIndex:f,vertices:0,numMorphTargets:i,numMorphNormals:j})),this.geometryGroups[g].faces3.push(c),this.geometryGroups[g].vertices+=3;this.geometryGroupsList=[];for(var k in this.geometryGroups)this.geometryGroups[k].id=a++,this.geometryGroupsList.push(this.geometryGroups[k])}}(),clone:function(){for(var a=new e.Geometry,b=this.vertices,c=0,d=b.length;d>c;c++)a.vertices.push(b[c].clone());for(var f=this.faces,c=0,d=f.length;d>c;c++)a.faces.push(f[c].clone());for(var g=this.faceVertexUvs[0],c=0,d=g.length;d>c;c++){for(var h=g[c],i=[],j=0,k=h.length;k>j;j++)i.push(new e.Vector2(h[j].x,h[j].y));a.faceVertexUvs[0].push(i)}return a},dispose:function(){this.dispatchEvent({type:"dispose"})}},e.EventDispatcher.prototype.apply(e.Geometry.prototype),e.GeometryIdCount=0,e.Geometry2=function(a){e.BufferGeometry.call(this),this.vertices=this.addAttribute("position",Float32Array,a,3).array,this.normals=this.addAttribute("normal",Float32Array,a,3).array,this.uvs=this.addAttribute("uv",Float32Array,a,2).array,this.boundingBox=null,this.boundingSphere=null},e.Geometry2.prototype=Object.create(e.BufferGeometry.prototype),e.Camera=function(){e.Object3D.call(this),this.matrixWorldInverse=new e.Matrix4,this.projectionMatrix=new e.Matrix4},e.Camera.prototype=Object.create(e.Object3D.prototype),e.Camera.prototype.lookAt=function(){var a=new e.Matrix4;return function(b){a.lookAt(this.position,b,this.up),this.quaternion.setFromRotationMatrix(a)}}(),e.Camera.prototype.clone=function(a){return void 0===a&&(a=new e.Camera),e.Object3D.prototype.clone.call(this,a),a.matrixWorldInverse.copy(this.matrixWorldInverse),a.projectionMatrix.copy(this.projectionMatrix),a},e.OrthographicCamera=function(a,b,c,d,f,g){e.Camera.call(this),this.left=a,this.right=b,this.top=c,this.bottom=d,this.near=void 0!==f?f:.1,this.far=void 0!==g?g:2e3,this.updateProjectionMatrix()},e.OrthographicCamera.prototype=Object.create(e.Camera.prototype),e.OrthographicCamera.prototype.updateProjectionMatrix=function(){this.projectionMatrix.makeOrthographic(this.left,this.right,this.top,this.bottom,this.near,this.far)},e.OrthographicCamera.prototype.clone=function(){var a=new e.OrthographicCamera;return e.Camera.prototype.clone.call(this,a),a.left=this.left,a.right=this.right,a.top=this.top,a.bottom=this.bottom,a.near=this.near,a.far=this.far,a},e.PerspectiveCamera=function(a,b,c,d){e.Camera.call(this),this.fov=void 0!==a?a:50,this.aspect=void 0!==b?b:1,this.near=void 0!==c?c:.1,this.far=void 0!==d?d:2e3,this.updateProjectionMatrix()},e.PerspectiveCamera.prototype=Object.create(e.Camera.prototype),e.PerspectiveCamera.prototype.setLens=function(a,b){void 0===b&&(b=24),this.fov=2*e.Math.radToDeg(Math.atan(b/(2*a))),this.updateProjectionMatrix()},e.PerspectiveCamera.prototype.setViewOffset=function(a,b,c,d,e,f){this.fullWidth=a,this.fullHeight=b,this.x=c,this.y=d,this.width=e,this.height=f,this.updateProjectionMatrix()},e.PerspectiveCamera.prototype.updateProjectionMatrix=function(){if(this.fullWidth){var a=this.fullWidth/this.fullHeight,b=Math.tan(e.Math.degToRad(.5*this.fov))*this.near,c=-b,d=a*c,f=a*b,g=Math.abs(f-d),h=Math.abs(b-c);this.projectionMatrix.makeFrustum(d+this.x*g/this.fullWidth,d+(this.x+this.width)*g/this.fullWidth,b-(this.y+this.height)*h/this.fullHeight,b-this.y*h/this.fullHeight,this.near,this.far)}else this.projectionMatrix.makePerspective(this.fov,this.aspect,this.near,this.far)},e.PerspectiveCamera.prototype.clone=function(){var a=new e.PerspectiveCamera;return e.Camera.prototype.clone.call(this,a),a.fov=this.fov,a.aspect=this.aspect,a.near=this.near,a.far=this.far,a},e.Light=function(a){e.Object3D.call(this),this.color=new e.Color(a)},e.Light.prototype=Object.create(e.Object3D.prototype),e.Light.prototype.clone=function(a){return void 0===a&&(a=new e.Light),e.Object3D.prototype.clone.call(this,a),a.color.copy(this.color),a},e.AmbientLight=function(a){e.Light.call(this,a)},e.AmbientLight.prototype=Object.create(e.Light.prototype),e.AmbientLight.prototype.clone=function(){var a=new e.AmbientLight;return e.Light.prototype.clone.call(this,a),a},e.AreaLight=function(a,b){e.Light.call(this,a),this.normal=new e.Vector3(0,-1,0),this.right=new e.Vector3(1,0,0),this.intensity=void 0!==b?b:1,this.width=1,this.height=1,this.constantAttenuation=1.5,this.linearAttenuation=.5,this.quadraticAttenuation=.1},e.AreaLight.prototype=Object.create(e.Light.prototype),e.DirectionalLight=function(a,b){e.Light.call(this,a),this.position.set(0,1,0),this.target=new e.Object3D,this.intensity=void 0!==b?b:1,this.castShadow=!1,this.onlyShadow=!1,this.shadowCameraNear=50,this.shadowCameraFar=5e3,this.shadowCameraLeft=-500,this.shadowCameraRight=500,this.shadowCameraTop=500,this.shadowCameraBottom=-500,this.shadowCameraVisible=!1,this.shadowBias=0,this.shadowDarkness=.5,this.shadowMapWidth=512,this.shadowMapHeight=512,this.shadowCascade=!1,this.shadowCascadeOffset=new e.Vector3(0,0,-1e3),this.shadowCascadeCount=2,this.shadowCascadeBias=[0,0,0],this.shadowCascadeWidth=[512,512,512],this.shadowCascadeHeight=[512,512,512],this.shadowCascadeNearZ=[-1,.99,.998],this.shadowCascadeFarZ=[.99,.998,1],this.shadowCascadeArray=[],this.shadowMap=null,this.shadowMapSize=null,this.shadowCamera=null,this.shadowMatrix=null},e.DirectionalLight.prototype=Object.create(e.Light.prototype),e.DirectionalLight.prototype.clone=function(){var a=new e.DirectionalLight;return e.Light.prototype.clone.call(this,a),a.target=this.target.clone(),a.intensity=this.intensity,a.castShadow=this.castShadow,a.onlyShadow=this.onlyShadow,a},e.HemisphereLight=function(a,b,c){e.Light.call(this,a),this.position.set(0,100,0),this.groundColor=new e.Color(b),this.intensity=void 0!==c?c:1},e.HemisphereLight.prototype=Object.create(e.Light.prototype),e.HemisphereLight.prototype.clone=function(){var a=new e.HemisphereLight;return e.Light.prototype.clone.call(this,a),a.groundColor.copy(this.groundColor),a.intensity=this.intensity,a},e.PointLight=function(a,b,c){e.Light.call(this,a),this.intensity=void 0!==b?b:1,this.distance=void 0!==c?c:0},e.PointLight.prototype=Object.create(e.Light.prototype),e.PointLight.prototype.clone=function(){var a=new e.PointLight;return e.Light.prototype.clone.call(this,a),a.intensity=this.intensity,a.distance=this.distance,a},e.SpotLight=function(a,b,c,d,f){e.Light.call(this,a),this.position.set(0,1,0),this.target=new e.Object3D,this.intensity=void 0!==b?b:1,this.distance=void 0!==c?c:0,this.angle=void 0!==d?d:Math.PI/3,this.exponent=void 0!==f?f:10,this.castShadow=!1,this.onlyShadow=!1,this.shadowCameraNear=50,this.shadowCameraFar=5e3,this.shadowCameraFov=50,this.shadowCameraVisible=!1,this.shadowBias=0,this.shadowDarkness=.5,this.shadowMapWidth=512,this.shadowMapHeight=512,this.shadowMap=null,this.shadowMapSize=null,this.shadowCamera=null,this.shadowMatrix=null},e.SpotLight.prototype=Object.create(e.Light.prototype),e.SpotLight.prototype.clone=function(){var a=new e.SpotLight;return e.Light.prototype.clone.call(this,a),a.target=this.target.clone(),a.intensity=this.intensity,a.distance=this.distance,a.angle=this.angle,a.exponent=this.exponent,a.castShadow=this.castShadow,a.onlyShadow=this.onlyShadow,a},e.Loader=function(a){this.showStatus=a,this.statusDomElement=a?e.Loader.prototype.addStatusElement():null,this.onLoadStart=function(){},this.onLoadProgress=function(){},this.onLoadComplete=function(){}},e.Loader.prototype={constructor:e.Loader,crossOrigin:void 0,addStatusElement:function(){var a=document.createElement("div");return a.style.position="absolute",a.style.right="0px",a.style.top="0px",a.style.fontSize="0.8em",a.style.textAlign="left",a.style.background="rgba(0,0,0,0.25)",a.style.color="#fff",a.style.width="120px",a.style.padding="0.5em 0.5em 0.5em 0.5em",a.style.zIndex=1e3,a.innerHTML="Loading ...",a},updateProgress:function(a){var b="Loaded ";b+=a.total?(100*a.loaded/a.total).toFixed(0)+"%":(a.loaded/1e3).toFixed(2)+" KB",this.statusDomElement.innerHTML=b},extractUrlBase:function(a){var b=a.split("/");return 1===b.length?"./":(b.pop(),b.join("/")+"/")},initMaterials:function(a,b){for(var c=[],d=0;db;b++){var d=a[b];if(d instanceof e.ShaderMaterial)return!0}return!1},createMaterial:function(a,b){function c(a){var b=Math.log(a)/Math.LN2;return Math.floor(b)==b}function d(a){var b=Math.log(a)/Math.LN2;return Math.pow(2,Math.round(b))}function f(a,b){var e=new Image;e.onload=function(){if(c(this.width)&&c(this.height))a.image=this;else{var b=d(this.width),e=d(this.height);a.image.width=b,a.image.height=e,a.image.getContext("2d").drawImage(this,0,0,b,e)}a.needsUpdate=!0},void 0!==i.crossOrigin&&(e.crossOrigin=i.crossOrigin),e.src=b}function g(a,c,d,g,h,i,j){var k=/\.dds$/i.test(d),l=b+d;if(k){var m=e.ImageUtils.loadCompressedTexture(l);a[c]=m}else{var m=document.createElement("canvas");a[c]=new e.Texture(m)}if(a[c].sourceFile=d,g&&(a[c].repeat.set(g[0],g[1]),1!==g[0]&&(a[c].wrapS=e.RepeatWrapping),1!==g[1]&&(a[c].wrapT=e.RepeatWrapping)),h&&a[c].offset.set(h[0],h[1]),i){var n={repeat:e.RepeatWrapping,mirror:e.MirroredRepeatWrapping};void 0!==n[i[0]]&&(a[c].wrapS=n[i[0]]),void 0!==n[i[1]]&&(a[c].wrapT=n[i[1]])}j&&(a[c].anisotropy=j),k||f(a[c],l)}function h(a){return(255*a[0]<<16)+(255*a[1]<<8)+255*a[2]}var i=this,j="MeshLambertMaterial",k={color:15658734,opacity:1,map:null,lightMap:null,normalMap:null,bumpMap:null,wireframe:!1};if(a.shading){var l=a.shading.toLowerCase();"phong"===l?j="MeshPhongMaterial":"basic"===l&&(j="MeshBasicMaterial")}if(void 0!==a.blending&&void 0!==e[a.blending]&&(k.blending=e[a.blending]),(void 0!==a.transparent||a.opacity<1)&&(k.transparent=a.transparent),void 0!==a.depthTest&&(k.depthTest=a.depthTest),void 0!==a.depthWrite&&(k.depthWrite=a.depthWrite),void 0!==a.visible&&(k.visible=a.visible),void 0!==a.flipSided&&(k.side=e.BackSide),void 0!==a.doubleSided&&(k.side=e.DoubleSide),void 0!==a.wireframe&&(k.wireframe=a.wireframe),void 0!==a.vertexColors&&("face"===a.vertexColors?k.vertexColors=e.FaceColors:a.vertexColors&&(k.vertexColors=e.VertexColors)),a.colorDiffuse?k.color=h(a.colorDiffuse):a.DbgColor&&(k.color=a.DbgColor),a.colorSpecular&&(k.specular=h(a.colorSpecular)),a.colorAmbient&&(k.ambient=h(a.colorAmbient)),a.transparency&&(k.opacity=a.transparency),a.specularCoef&&(k.shininess=a.specularCoef),a.mapDiffuse&&b&&g(k,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap,a.mapDiffuseAnisotropy),a.mapLight&&b&&g(k,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy),a.mapBump&&b&&g(k,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy),a.mapNormal&&b&&g(k,"normalMap",a.mapNormal,a.mapNormalRepeat,a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy),a.mapSpecular&&b&&g(k,"specularMap",a.mapSpecular,a.mapSpecularRepeat,a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy),a.mapBumpScale&&(k.bumpScale=a.mapBumpScale),a.mapNormal){var m=e.ShaderLib.normalmap,n=e.UniformsUtils.clone(m.uniforms);n.tNormal.value=k.normalMap,a.mapNormalFactor&&n.uNormalScale.value.set(a.mapNormalFactor,a.mapNormalFactor),k.map&&(n.tDiffuse.value=k.map,n.enableDiffuse.value=!0),k.specularMap&&(n.tSpecular.value=k.specularMap,n.enableSpecular.value=!0),k.lightMap&&(n.tAO.value=k.lightMap,n.enableAO.value=!0),n.diffuse.value.setHex(k.color),n.specular.value.setHex(k.specular),n.ambient.value.setHex(k.ambient),n.shininess.value=k.shininess,void 0!==k.opacity&&(n.opacity.value=k.opacity);var o={fragmentShader:m.fragmentShader,vertexShader:m.vertexShader,uniforms:n,lights:!0,fog:!0},p=new e.ShaderMaterial(o);k.transparent&&(p.transparent=!0)}else var p=new e[j](k);return void 0!==a.DbgName&&(p.name=a.DbgName),p}},e.XHRLoader=function(a){this.manager=void 0!==a?a:e.DefaultLoadingManager},e.XHRLoader.prototype={constructor:e.XHRLoader,load:function(a,b,c,d){var e=this,f=new XMLHttpRequest;void 0!==b&&f.addEventListener("load",function(c){b(c.target.responseText),e.manager.itemEnd(a)},!1),void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1),void 0!==d&&f.addEventListener("error",function(a){d(a)},!1),void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin),f.open("GET",a,!0),f.send(null),e.manager.itemStart(a)},setCrossOrigin:function(a){this.crossOrigin=a}},e.ImageLoader=function(a){this.manager=void 0!==a?a:e.DefaultLoadingManager},e.ImageLoader.prototype={constructor:e.ImageLoader,load:function(a,b,c,d){var e=this,f=document.createElement("img");return void 0!==b&&f.addEventListener("load",function(){e.manager.itemEnd(a),b(this)},!1),void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1),void 0!==d&&f.addEventListener("error",function(a){d(a)},!1),void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin),f.src=a,e.manager.itemStart(a),f},setCrossOrigin:function(a){this.crossOrigin=a}},e.JSONLoader=function(a){e.Loader.call(this,a),this.withCredentials=!1},e.JSONLoader.prototype=Object.create(e.Loader.prototype),e.JSONLoader.prototype.load=function(a,b,c){c=c&&"string"==typeof c?c:this.extractUrlBase(a),this.onLoadStart(),this.loadAjaxJSON(this,a,b,c)},e.JSONLoader.prototype.loadAjaxJSON=function(a,b,c,d,e){var f=new XMLHttpRequest,g=0;f.onreadystatechange=function(){if(f.readyState===f.DONE)if(200===f.status||0===f.status){if(f.responseText){var h=JSON.parse(f.responseText);if("scene"===h.metadata.type)return void console.error('THREE.JSONLoader: "'+b+'" seems to be a Scene. Use THREE.SceneLoader instead.');var i=a.parse(h,d);c(i.geometry,i.materials)}else console.error('THREE.JSONLoader: "'+b+'" seems to be unreachable or the file is empty.');a.onLoadComplete()}else console.error("THREE.JSONLoader: Couldn't load \""+b+'" ('+f.status+")");else f.readyState===f.LOADING?e&&(0===g&&(g=f.getResponseHeader("Content-Length")),e({total:g,loaded:f.responseText.length})):f.readyState===f.HEADERS_RECEIVED&&void 0!==e&&(g=f.getResponseHeader("Content-Length"))},f.open("GET",b,!0),f.withCredentials=this.withCredentials,f.send(null)},e.JSONLoader.prototype.parse=function(a,b){function c(b){function c(a,b){return a&1<d;d++)g.faceVertexUvs[d]=[]}for(i=0,j=H.length;j>i;)w=new e.Vector3,w.x=H[i++]*b,w.y=H[i++]*b,w.z=H[i++]*b,g.vertices.push(w);for(i=0,j=G.length;j>i;)if(o=G[i++],p=c(o,0),q=c(o,1),r=c(o,3),s=c(o,4),t=c(o,5),u=c(o,6),v=c(o,7),p){if(y=new e.Face3,y.a=G[i],y.b=G[i+1],y.c=G[i+3],z=new e.Face3,z.a=G[i+1],z.b=G[i+2],z.c=G[i+3],i+=4,q&&(n=G[i++],y.materialIndex=n,z.materialIndex=n),h=g.faces.length,r)for(d=0;K>d;d++)for(C=a.uvs[d],g.faceVertexUvs[d][h]=[],g.faceVertexUvs[d][h+1]=[],f=0;4>f;f++)m=G[i++],E=C[2*m],F=C[2*m+1],D=new e.Vector2(E,F),2!==f&&g.faceVertexUvs[d][h].push(D),0!==f&&g.faceVertexUvs[d][h+1].push(D);if(s&&(l=3*G[i++],y.normal.set(I[l++],I[l++],I[l]),z.normal.copy(y.normal)),t)for(d=0;4>d;d++)l=3*G[i++],B=new e.Vector3(I[l++],I[l++],I[l]),2!==d&&y.vertexNormals.push(B),0!==d&&z.vertexNormals.push(B);if(u&&(k=G[i++],A=J[k],y.color.setHex(A),z.color.setHex(A)),v)for(d=0;4>d;d++)k=G[i++],A=J[k],2!==d&&y.vertexColors.push(new e.Color(A)),0!==d&&z.vertexColors.push(new e.Color(A));g.faces.push(y),g.faces.push(z)}else{if(x=new e.Face3,x.a=G[i++],x.b=G[i++],x.c=G[i++],q&&(n=G[i++],x.materialIndex=n),h=g.faces.length,r)for(d=0;K>d;d++)for(C=a.uvs[d],g.faceVertexUvs[d][h]=[],f=0;3>f;f++)m=G[i++],E=C[2*m],F=C[2*m+1],D=new e.Vector2(E,F),g.faceVertexUvs[d][h].push(D);if(s&&(l=3*G[i++],x.normal.set(I[l++],I[l++],I[l])),t)for(d=0;3>d;d++)l=3*G[i++],B=new e.Vector3(I[l++],I[l++],I[l]),x.vertexNormals.push(B);if(u&&(k=G[i++],x.color.setHex(J[k])),v)for(d=0;3>d;d++)k=G[i++],x.vertexColors.push(new e.Color(J[k]));g.faces.push(x)}}function d(){if(a.skinWeights)for(var b=0,c=a.skinWeights.length;c>b;b+=2){var d=a.skinWeights[b],f=a.skinWeights[b+1],h=0,i=0;g.skinWeights.push(new e.Vector4(d,f,h,i))}if(a.skinIndices)for(var b=0,c=a.skinIndices.length;c>b;b+=2){var j=a.skinIndices[b],k=a.skinIndices[b+1],l=0,m=0;g.skinIndices.push(new e.Vector4(j,k,l,m))}g.bones=a.bones,g.bones&&g.bones.length>0&&(g.skinWeights.length!==g.skinIndices.length||g.skinIndices.length!==g.vertices.length)&&console.warn("When skinning, number of vertices ("+g.vertices.length+"), skinIndices ("+g.skinIndices.length+"), and skinWeights ("+g.skinWeights.length+") should match."),g.animation=a.animation,g.animations=a.animations}function f(b){if(void 0!==a.morphTargets){var c,d,f,h,i,j;for(c=0,d=a.morphTargets.length;d>c;c++)for(g.morphTargets[c]={},g.morphTargets[c].name=a.morphTargets[c].name,g.morphTargets[c].vertices=[],i=g.morphTargets[c].vertices,j=a.morphTargets[c].vertices,f=0,h=j.length;h>f;f+=3){var k=new e.Vector3;k.x=j[f]*b,k.y=j[f+1]*b,k.z=j[f+2]*b,i.push(k)}}if(void 0!==a.morphColors){var c,d,l,m,n,o,p;for(c=0,d=a.morphColors.length;d>c;c++)for(g.morphColors[c]={},g.morphColors[c].name=a.morphColors[c].name,g.morphColors[c].colors=[],n=g.morphColors[c].colors,o=a.morphColors[c].colors,l=0,m=o.length;m>l;l+=3)p=new e.Color(16755200),p.setRGB(o[l],o[l+1],o[l+2]),n.push(p)}}var g=new e.Geometry,h=void 0!==a.scale?1/a.scale:1;if(c(h),d(),f(h),g.computeCentroids(),g.computeFaceNormals(),g.computeBoundingSphere(),void 0===a.materials)return{geometry:g};var i=this.initMaterials(a.materials,b);return this.needsTangents(i)&&g.computeTangents(),{geometry:g,materials:i}},e.LoadingManager=function(a,b,c){var d=this,e=0,f=0;this.onLoad=a,this.onProgress=b,this.onError=c,this.itemStart=function(){f++},this.itemEnd=function(a){e++,void 0!==d.onProgress&&d.onProgress(a,e,f),e===f&&void 0!==d.onLoad&&d.onLoad()}},e.DefaultLoadingManager=new e.LoadingManager,e.BufferGeometryLoader=function(a){this.manager=void 0!==a?a:e.DefaultLoadingManager},e.BufferGeometryLoader.prototype={constructor:e.BufferGeometryLoader,load:function(a,b){var c=this,d=new e.XHRLoader;d.setCrossOrigin(this.crossOrigin),d.load(a,function(a){b(c.parse(JSON.parse(a)))})},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=new e.BufferGeometry,c=a.attributes,f=a.offsets,g=a.boundingSphere;for(var h in c){var i=c[h];b.attributes[h]={itemSize:i.itemSize,array:new d[i.type](i.array)}}return void 0!==f&&(b.offsets=JSON.parse(JSON.stringify(f))),void 0!==g&&(b.boundingSphere=new e.Sphere((new e.Vector3).fromArray(void 0!==g.center?g.center:[0,0,0]),g.radius)),b}},e.Geometry2Loader=function(a){this.manager=void 0!==a?a:e.DefaultLoadingManager},e.Geometry2Loader.prototype={constructor:e.Geometry2Loader,load:function(a,b){var c=this,d=new e.XHRLoader;d.setCrossOrigin(this.crossOrigin),d.load(a,function(a){b(c.parse(JSON.parse(a)))})},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=new e.Geometry2(a.vertices.length/3),c=["vertices","normals","uvs"],d=a.boundingSphere;for(var f in c){var g=c[f];b[g].set(a[g])}return void 0!==d&&(b.boundingSphere=new e.Sphere((new e.Vector3).fromArray(void 0!==d.center?d.center:[0,0,0]),d.radius)),b}},e.MaterialLoader=function(a){this.manager=void 0!==a?a:e.DefaultLoadingManager},e.MaterialLoader.prototype={constructor:e.MaterialLoader,load:function(a,b){var c=this,d=new e.XHRLoader;d.setCrossOrigin(this.crossOrigin),d.load(a,function(a){b(c.parse(JSON.parse(a)))})},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=new e[a.type];if(void 0!==a.color&&b.color.setHex(a.color),void 0!==a.ambient&&b.ambient.setHex(a.ambient),void 0!==a.emissive&&b.emissive.setHex(a.emissive),void 0!==a.specular&&b.specular.setHex(a.specular),void 0!==a.shininess&&(b.shininess=a.shininess),void 0!==a.vertexColors&&(b.vertexColors=a.vertexColors),void 0!==a.blending&&(b.blending=a.blending),void 0!==a.side&&(b.side=a.side),void 0!==a.opacity&&(b.opacity=a.opacity),void 0!==a.transparent&&(b.transparent=a.transparent),void 0!==a.wireframe&&(b.wireframe=a.wireframe),void 0!==a.materials)for(var c=0,d=a.materials.length;d>c;c++)b.materials.push(this.parse(a.materials[c]));return b}},e.ObjectLoader=function(a){this.manager=void 0!==a?a:e.DefaultLoadingManager},e.ObjectLoader.prototype={constructor:e.ObjectLoader,load:function(a,b){var c=this,d=new e.XHRLoader(c.manager);d.setCrossOrigin(this.crossOrigin),d.load(a,function(a){b(c.parse(JSON.parse(a)))})},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=this.parseGeometries(a.geometries),c=this.parseMaterials(a.materials),d=this.parseObject(a.object,b,c);return d},parseGeometries:function(a){var b={};if(void 0!==a)for(var c=new e.JSONLoader,d=new e.Geometry2Loader,f=new e.BufferGeometryLoader,g=0,h=a.length;h>g;g++){var i,j=a[g];switch(j.type){case"PlaneGeometry":i=new e.PlaneGeometry(j.width,j.height,j.widthSegments,j.heightSegments);break;case"BoxGeometry":case"CubeGeometry":i=new e.BoxGeometry(j.width,j.height,j.depth,j.widthSegments,j.heightSegments,j.depthSegments);break;case"CircleGeometry":i=new e.CircleGeometry(j.radius,j.segments);break;case"CylinderGeometry":i=new e.CylinderGeometry(j.radiusTop,j.radiusBottom,j.height,j.radialSegments,j.heightSegments,j.openEnded);break;case"SphereGeometry":i=new e.SphereGeometry(j.radius,j.widthSegments,j.heightSegments,j.phiStart,j.phiLength,j.thetaStart,j.thetaLength);break;case"IcosahedronGeometry":i=new e.IcosahedronGeometry(j.radius,j.detail);break;case"TorusGeometry":i=new e.TorusGeometry(j.radius,j.tube,j.radialSegments,j.tubularSegments,j.arc);break;case"TorusKnotGeometry":i=new e.TorusKnotGeometry(j.radius,j.tube,j.radialSegments,j.tubularSegments,j.p,j.q,j.heightScale);break;case"BufferGeometry":i=f.parse(j.data);break;case"Geometry2":i=d.parse(j.data);break;case"Geometry":i=c.parse(j.data).geometry}i.uuid=j.uuid,void 0!==j.name&&(i.name=j.name),b[j.uuid]=i}return b},parseMaterials:function(a){var b={};if(void 0!==a)for(var c=new e.MaterialLoader,d=0,f=a.length;f>d;d++){var g=a[d],h=c.parse(g);h.uuid=g.uuid,void 0!==g.name&&(h.name=g.name),b[g.uuid]=h}return b},parseObject:function(){var a=new e.Matrix4;return function(b,c,d){var f;switch(b.type){case"Scene":f=new e.Scene;break;case"PerspectiveCamera":f=new e.PerspectiveCamera(b.fov,b.aspect,b.near,b.far);break;case"OrthographicCamera":f=new e.OrthographicCamera(b.left,b.right,b.top,b.bottom,b.near,b.far);break;case"AmbientLight":f=new e.AmbientLight(b.color);break;case"DirectionalLight":f=new e.DirectionalLight(b.color,b.intensity);break;case"PointLight":f=new e.PointLight(b.color,b.intensity,b.distance);break;case"SpotLight":f=new e.SpotLight(b.color,b.intensity,b.distance,b.angle,b.exponent);break;case"HemisphereLight":f=new e.HemisphereLight(b.color,b.groundColor,b.intensity);break;case"Mesh":var g=c[b.geometry],h=d[b.material];void 0===g&&console.error("THREE.ObjectLoader: Undefined geometry "+b.geometry),void 0===h&&console.error("THREE.ObjectLoader: Undefined material "+b.material),f=new e.Mesh(g,h);break;case"Sprite":var h=d[b.material];void 0===h&&console.error("THREE.ObjectLoader: Undefined material "+b.material),f=new e.Sprite(h);break;default:f=new e.Object3D}if(f.uuid=b.uuid,void 0!==b.name&&(f.name=b.name),void 0!==b.matrix?(a.fromArray(b.matrix),a.decompose(f.position,f.quaternion,f.scale)):(void 0!==b.position&&f.position.fromArray(b.position),void 0!==b.rotation&&f.rotation.fromArray(b.rotation),void 0!==b.scale&&f.scale.fromArray(b.scale)),void 0!==b.visible&&(f.visible=b.visible),void 0!==b.userData&&(f.userData=b.userData),void 0!==b.children)for(var i in b.children)f.add(this.parseObject(b.children[i],c,d));return f}}()},e.SceneLoader=function(){this.onLoadStart=function(){},this.onLoadProgress=function(){},this.onLoadComplete=function(){},this.callbackSync=function(){},this.callbackProgress=function(){},this.geometryHandlers={},this.hierarchyHandlers={},this.addGeometryHandler("ascii",e.JSONLoader) -},e.SceneLoader.prototype={constructor:e.SceneLoader,load:function(a,b){var c=this,d=new e.XHRLoader(c.manager);d.setCrossOrigin(this.crossOrigin),d.load(a,function(d){c.parse(JSON.parse(d),b,a)})},setCrossOrigin:function(a){this.crossOrigin=a},addGeometryHandler:function(a,b){this.geometryHandlers[a]={loaderClass:b}},addHierarchyHandler:function(a,b){this.hierarchyHandlers[a]={loaderClass:b}},parse:function(a,b,c){function d(a,b){return"relativeToHTML"==b?a:C+a}function f(){g(A.scene,E.objects)}function g(a,b){var c,f,h,i,j;for(var l in b){var m=A.objects[l],n=b[l];if(void 0===m){if(n.type&&n.type in B.hierarchyHandlers){if(void 0===n.loading){var o={type:1,url:1,material:1,position:1,rotation:1,scale:1,visible:1,children:1,userData:1,skin:1,morph:1,mirroredLoop:1,duration:1},s={};for(var t in n)t in o||(s[t]=n[t]);q=A.materials[n.material],n.loading=!0;var u=B.hierarchyHandlers[n.type].loaderObject;u.options?u.load(d(n.url,E.urlBaseType),k(l,a,q,n)):u.load(d(n.url,E.urlBaseType),k(l,a,q,n),s)}}else if(void 0!==n.geometry){if(p=A.geometries[n.geometry]){var w=!1;if(q=A.materials[n.material],w=q instanceof e.ShaderMaterial,f=n.position,h=n.rotation,i=n.scale,c=n.matrix,j=n.quaternion,n.material||(q=new e.MeshFaceMaterial(A.face_materials[n.geometry])),q instanceof e.MeshFaceMaterial&&0===q.materials.length&&(q=new e.MeshFaceMaterial(A.face_materials[n.geometry])),q instanceof e.MeshFaceMaterial)for(var x=0;xbb;bb++)ab[bb]=d(Z.url[bb],E.urlBaseType);var cb=/\.dds$/i.test(ab[0]);t=cb?e.ImageUtils.loadCompressedTextureCube(ab,Z.mapping,N(_)):e.ImageUtils.loadTextureCube(ab,Z.mapping,N(_))}else{var cb=/\.dds$/i.test(Z.url),db=d(Z.url,E.urlBaseType),eb=N(1);if(t=cb?e.ImageUtils.loadCompressedTexture(db,Z.mapping,eb):e.ImageUtils.loadTexture(db,Z.mapping,eb),void 0!==e[Z.minFilter]&&(t.minFilter=e[Z.minFilter]),void 0!==e[Z.magFilter]&&(t.magFilter=e[Z.magFilter]),Z.anisotropy&&(t.anisotropy=Z.anisotropy),Z.repeat&&(t.repeat.set(Z.repeat[0],Z.repeat[1]),1!==Z.repeat[0]&&(t.wrapS=e.RepeatWrapping),1!==Z.repeat[1]&&(t.wrapT=e.RepeatWrapping)),Z.offset&&t.offset.set(Z.offset[0],Z.offset[1]),Z.wrap){var fb={repeat:e.RepeatWrapping,mirror:e.MirroredRepeatWrapping};void 0!==fb[Z.wrap[0]]&&(t.wrapS=fb[Z.wrap[0]]),void 0!==fb[Z.wrap[1]]&&(t.wrapT=fb[Z.wrap[1]])}}A.textures[Y]=t}var gb,hb,ib;for(gb in E.materials){hb=E.materials[gb];for(ib in hb.parameters)if("envMap"===ib||"map"===ib||"lightMap"===ib||"bumpMap"===ib)hb.parameters[ib]=A.textures[hb.parameters[ib]];else if("shading"===ib)hb.parameters[ib]="flat"===hb.parameters[ib]?e.FlatShading:e.SmoothShading;else if("side"===ib)hb.parameters[ib]="double"==hb.parameters[ib]?e.DoubleSide:"back"==hb.parameters[ib]?e.BackSide:e.FrontSide;else if("blending"===ib)hb.parameters[ib]=hb.parameters[ib]in e?e[hb.parameters[ib]]:e.NormalBlending;else if("combine"===ib)hb.parameters[ib]=hb.parameters[ib]in e?e[hb.parameters[ib]]:e.MultiplyOperation;else if("vertexColors"===ib)"face"==hb.parameters[ib]?hb.parameters[ib]=e.FaceColors:hb.parameters[ib]&&(hb.parameters[ib]=e.VertexColors);else if("wrapRGB"===ib){var jb=hb.parameters[ib];hb.parameters[ib]=new e.Vector3(jb[0],jb[1],jb[2])}if(void 0!==hb.parameters.opacity&&hb.parameters.opacity<1&&(hb.parameters.transparent=!0),hb.parameters.normalMap){var kb=e.ShaderLib.normalmap,lb=e.UniformsUtils.clone(kb.uniforms),mb=hb.parameters.color,nb=hb.parameters.specular,ob=hb.parameters.ambient,pb=hb.parameters.shininess;lb.tNormal.value=A.textures[hb.parameters.normalMap],hb.parameters.normalScale&&lb.uNormalScale.value.set(hb.parameters.normalScale[0],hb.parameters.normalScale[1]),hb.parameters.map&&(lb.tDiffuse.value=hb.parameters.map,lb.enableDiffuse.value=!0),hb.parameters.envMap&&(lb.tCube.value=hb.parameters.envMap,lb.enableReflection.value=!0,lb.reflectivity.value=hb.parameters.reflectivity),hb.parameters.lightMap&&(lb.tAO.value=hb.parameters.lightMap,lb.enableAO.value=!0),hb.parameters.specularMap&&(lb.tSpecular.value=A.textures[hb.parameters.specularMap],lb.enableSpecular.value=!0),hb.parameters.displacementMap&&(lb.tDisplacement.value=A.textures[hb.parameters.displacementMap],lb.enableDisplacement.value=!0,lb.uDisplacementBias.value=hb.parameters.displacementBias,lb.uDisplacementScale.value=hb.parameters.displacementScale),lb.diffuse.value.setHex(mb),lb.specular.value.setHex(nb),lb.ambient.value.setHex(ob),lb.shininess.value=pb,hb.parameters.opacity&&(lb.opacity.value=hb.parameters.opacity);var qb={fragmentShader:kb.fragmentShader,vertexShader:kb.vertexShader,uniforms:lb,lights:!0,fog:!0};q=new e.ShaderMaterial(qb)}else q=new e[hb.type](hb.parameters);q.name=gb,A.materials[gb]=q}for(gb in E.materials)if(hb=E.materials[gb],hb.parameters.materials){for(var rb=[],bb=0;bb0){this.morphTargetBase=-1,this.morphTargetForcedOrder=[],this.morphTargetInfluences=[],this.morphTargetDictionary={};for(var a=0,b=this.geometry.morphTargets.length;b>a;a++)this.morphTargetInfluences.push(0),this.morphTargetDictionary[this.geometry.morphTargets[a].name]=a}},e.Mesh.prototype.getMorphTargetIndexByName=function(a){return void 0!==this.morphTargetDictionary[a]?this.morphTargetDictionary[a]:(console.log("THREE.Mesh.getMorphTargetIndexByName: morph target "+a+" does not exist. Returning 0."),0)},e.Mesh.prototype.clone=function(a){return void 0===a&&(a=new e.Mesh(this.geometry,this.material)),e.Object3D.prototype.clone.call(this,a),a},e.Bone=function(a){e.Object3D.call(this),this.skin=a,this.skinMatrix=new e.Matrix4},e.Bone.prototype=Object.create(e.Object3D.prototype),e.Bone.prototype.update=function(a,b){this.matrixAutoUpdate&&(b|=this.updateMatrix()),(b||this.matrixWorldNeedsUpdate)&&(a?this.skinMatrix.multiplyMatrices(a,this.matrix):this.skinMatrix.copy(this.matrix),this.matrixWorldNeedsUpdate=!1,b=!0);var c,d=this.children.length;for(c=0;d>c;c++)this.children[c].update(this.skinMatrix,b)},e.SkinnedMesh=function(a,b,c){e.Mesh.call(this,a,b),this.useVertexTexture=void 0!==c?c:!0,this.identityMatrix=new e.Matrix4,this.bones=[],this.boneMatrices=[];var d,f,g,h,i,j;if(this.geometry&&void 0!==this.geometry.bones){for(d=0;d256?64:k>64?32:k>16?16:8,this.boneTextureWidth=l,this.boneTextureHeight=l,this.boneMatrices=new Float32Array(this.boneTextureWidth*this.boneTextureHeight*4),this.boneTexture=new e.DataTexture(this.boneMatrices,this.boneTextureWidth,this.boneTextureHeight,e.RGBAFormat,e.FloatType),this.boneTexture.minFilter=e.NearestFilter,this.boneTexture.magFilter=e.NearestFilter,this.boneTexture.generateMipmaps=!1,this.boneTexture.flipY=!1}else this.boneMatrices=new Float32Array(16*k);this.pose()}},e.SkinnedMesh.prototype=Object.create(e.Mesh.prototype),e.SkinnedMesh.prototype.addBone=function(a){return void 0===a&&(a=new e.Bone(this)),this.bones.push(a),a},e.SkinnedMesh.prototype.updateMatrixWorld=function(){var a=new e.Matrix4;return function(b){this.matrixAutoUpdate&&this.updateMatrix(),(this.matrixWorldNeedsUpdate||b)&&(this.parent?this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix):this.matrixWorld.copy(this.matrix),this.matrixWorldNeedsUpdate=!1,b=!0);for(var c=0,d=this.children.length;d>c;c++){var f=this.children[c];f instanceof e.Bone?f.update(this.identityMatrix,!1):f.updateMatrixWorld(!0)}if(void 0==this.boneInverses){this.boneInverses=[];for(var g=0,h=this.bones.length;h>g;g++){var i=new e.Matrix4;i.getInverse(this.bones[g].skinMatrix),this.boneInverses.push(i)}}for(var g=0,h=this.bones.length;h>g;g++)a.multiplyMatrices(this.bones[g].skinMatrix,this.boneInverses[g]),a.flattenToArrayOffset(this.boneMatrices,16*g);this.useVertexTexture&&(this.boneTexture.needsUpdate=!0)}}(),e.SkinnedMesh.prototype.pose=function(){this.updateMatrixWorld(!0),this.normalizeSkinWeights()},e.SkinnedMesh.prototype.normalizeSkinWeights=function(){if(this.geometry instanceof e.Geometry)for(var a=0;ae;e++){var g=a.morphTargets[e],h=g.name.match(d);if(h&&h.length>1){{var i=h[1];h[2]}c[i]||(c[i]={start:1/0,end:-1/0});var j=c[i];ej.end&&(j.end=e),b||(b=i)}}a.firstAnimation=b},e.MorphAnimMesh.prototype.setAnimationLabel=function(a,b,c){this.geometry.animations||(this.geometry.animations={}),this.geometry.animations[a]={start:b,end:c}},e.MorphAnimMesh.prototype.playAnimation=function(a,b){var c=this.geometry.animations[a];c?(this.setFrameRange(c.start,c.end),this.duration=1e3*((c.end-c.start)/b),this.time=0):console.warn("animation["+a+"] undefined")},e.MorphAnimMesh.prototype.updateAnimation=function(a){var b=this.duration/this.length;this.time+=this.direction*a,this.mirroredLoop?(this.time>this.duration||this.time<0)&&(this.direction*=-1,this.time>this.duration&&(this.time=this.duration,this.directionBackwards=!0),this.time<0&&(this.time=0,this.directionBackwards=!1)):(this.time=this.time%this.duration,this.time<0&&(this.time+=this.duration));var c=this.startKeyframe+e.Math.clamp(Math.floor(this.time/b),0,this.length-1);c!==this.currentKeyframe&&(this.morphTargetInfluences[this.lastKeyframe]=0,this.morphTargetInfluences[this.currentKeyframe]=1,this.morphTargetInfluences[c]=0,this.lastKeyframe=this.currentKeyframe,this.currentKeyframe=c);var d=this.time%b/b;this.directionBackwards&&(d=1-d),this.morphTargetInfluences[this.currentKeyframe]=d,this.morphTargetInfluences[this.lastKeyframe]=1-d},e.MorphAnimMesh.prototype.clone=function(a){return void 0===a&&(a=new e.MorphAnimMesh(this.geometry,this.material)),a.duration=this.duration,a.mirroredLoop=this.mirroredLoop,a.time=this.time,a.lastKeyframe=this.lastKeyframe,a.currentKeyframe=this.currentKeyframe,a.direction=this.direction,a.directionBackwards=this.directionBackwards,e.Mesh.prototype.clone.call(this,a),a -},e.LOD=function(){e.Object3D.call(this),this.objects=[]},e.LOD.prototype=Object.create(e.Object3D.prototype),e.LOD.prototype.addLevel=function(a,b){void 0===b&&(b=0),b=Math.abs(b);for(var c=0;cb&&!(a1){a.setFromMatrixPosition(c.matrixWorld),b.setFromMatrixPosition(this.matrixWorld);var d=a.distanceTo(b);this.objects[0].object.visible=!0;for(var e=1,f=this.objects.length;f>e&&d>=this.objects[e].distance;e++)this.objects[e-1].object.visible=!1,this.objects[e].object.visible=!0;for(;f>e;e++)this.objects[e].object.visible=!1}}}(),e.LOD.prototype.clone=function(a){void 0===a&&(a=new e.LOD),e.Object3D.prototype.clone.call(this,a);for(var b=0,c=this.objects.length;c>b;b++){var d=this.objects[b].object.clone();d.visible=0===b,a.addLevel(d,this.objects[b].distance)}return a},e.Sprite=function(){var a=new e.Geometry2(3);return a.vertices.set([-.5,-.5,0,.5,-.5,0,.5,.5,0]),function(b){e.Object3D.call(this),this.geometry=a,this.material=void 0!==b?b:new e.SpriteMaterial}}(),e.Sprite.prototype=Object.create(e.Object3D.prototype),e.Sprite.prototype.updateMatrix=function(){this.matrix.compose(this.position,this.quaternion,this.scale),this.matrixWorldNeedsUpdate=!0},e.Sprite.prototype.clone=function(a){return void 0===a&&(a=new e.Sprite(this.material)),e.Object3D.prototype.clone.call(this,a),a},e.Particle=e.Sprite,e.Scene=function(){e.Object3D.call(this),this.fog=null,this.overrideMaterial=null,this.autoUpdate=!0,this.matrixAutoUpdate=!1,this.__lights=[],this.__objectsAdded=[],this.__objectsRemoved=[]},e.Scene.prototype=Object.create(e.Object3D.prototype),e.Scene.prototype.__addObject=function(a){if(a instanceof e.Light)-1===this.__lights.indexOf(a)&&this.__lights.push(a),a.target&&void 0===a.target.parent&&this.add(a.target);else if(!(a instanceof e.Camera||a instanceof e.Bone)){this.__objectsAdded.push(a);var b=this.__objectsRemoved.indexOf(a);-1!==b&&this.__objectsRemoved.splice(b,1)}this.dispatchEvent({type:"objectAdded",object:a}),a.dispatchEvent({type:"addedToScene",scene:this});for(var c=0;ca;a++){var c=C[a],d=c.color;c instanceof e.AmbientLight?Gb.add(d):c instanceof e.DirectionalLight?Hb.add(d):c instanceof e.PointLight&&Ib.add(d)}}function c(a,b,c){for(var d=0,f=C.length;f>d;d++){var g=C[d];if(Bb.copy(g.color),g instanceof e.DirectionalLight){var h=Jb.setFromMatrixPosition(g.matrixWorld).normalize(),i=b.dot(h);if(0>=i)continue;i*=g.intensity,c.add(Bb.multiplyScalar(i))}else if(g instanceof e.PointLight){var h=Jb.setFromMatrixPosition(g.matrixWorld),i=b.dot(Jb.subVectors(h,a).normalize());if(0>=i)continue;if(i*=0==g.distance?1:1-Math.min(a.distanceTo(h)/g.distance,1),0==i)continue;i*=g.intensity,c.add(Bb.multiplyScalar(i))}}}function f(a,b,c){r(c.opacity),s(c.blending);var d=b.scale.x*gb,f=b.scale.y*hb,g=.5*Math.sqrt(d*d+f*f);if(Fb.min.set(a.x-g,a.y-g),Fb.max.set(a.x+g,a.y+g),c instanceof e.SpriteMaterial||c instanceof e.ParticleSystemMaterial){var h=c.map;if(null!==h){h.hasEventListener("update",l)===!1&&(void 0!==h.image&&h.image.width>0&&m(h),h.addEventListener("update",l));var i=Cb[h.id];x(void 0!==i?i:"rgba( 0, 0, 0, 1 )");var j=h.image,k=j.width*h.offset.x,n=j.height*h.offset.y,o=j.width*h.repeat.x,p=j.height*h.repeat.y,q=d/o,t=f/p;ib.save(),ib.translate(a.x,a.y),0!==c.rotation&&ib.rotate(c.rotation),ib.translate(-d/2,-f/2),ib.scale(q,t),ib.translate(-k,-n),ib.fillRect(k,n,o,p),ib.restore()}else x(c.color.getStyle()),ib.save(),ib.translate(a.x,a.y),0!==c.rotation&&ib.rotate(c.rotation),ib.scale(d,-f),ib.fillRect(-.5,-.5,1,1),ib.restore()}else c instanceof e.SpriteCanvasMaterial&&(w(c.color.getStyle()),x(c.color.getStyle()),ib.save(),ib.translate(a.x,a.y),0!==c.rotation&&ib.rotate(c.rotation),ib.scale(d,f),c.program(ib),ib.restore())}function g(a,b,c,d){if(r(d.opacity),s(d.blending),ib.beginPath(),ib.moveTo(a.positionScreen.x,a.positionScreen.y),ib.lineTo(b.positionScreen.x,b.positionScreen.y),d instanceof e.LineBasicMaterial){if(t(d.linewidth),u(d.linecap),v(d.linejoin),d.vertexColors!==e.VertexColors)w(d.color.getStyle());else{var f=c.vertexColors[0].getStyle(),g=c.vertexColors[1].getStyle();if(f===g)w(f);else{try{var h=ib.createLinearGradient(a.positionScreen.x,a.positionScreen.y,b.positionScreen.x,b.positionScreen.y);h.addColorStop(0,f),h.addColorStop(1,g)}catch(i){h=f}w(h)}}ib.stroke(),Fb.expandByScalar(2*d.linewidth)}else d instanceof e.LineDashedMaterial&&(t(d.linewidth),u(d.linecap),v(d.linejoin),w(d.color.getStyle()),y(d.dashSize,d.gapSize),ib.stroke(),Fb.expandByScalar(2*d.linewidth),y(null,null))}function h(a,b,d,f,g,h,l,m){bb.info.render.vertices+=3,bb.info.render.faces++,r(m.opacity),s(m.blending),H=a.positionScreen.x,I=a.positionScreen.y,J=b.positionScreen.x,K=b.positionScreen.y,L=d.positionScreen.x,M=d.positionScreen.y,i(H,I,J,K,L,M),(m instanceof e.MeshLambertMaterial||m instanceof e.MeshPhongMaterial)&&null===m.map?(zb.copy(m.color),Ab.copy(m.emissive),m.vertexColors===e.FaceColors&&zb.multiply(l.color),m.wireframe===!1&&m.shading===e.SmoothShading&&3===l.vertexNormalsLength?(vb.copy(Gb),wb.copy(Gb),xb.copy(Gb),c(l.v1.positionWorld,l.vertexNormalsModel[0],vb),c(l.v2.positionWorld,l.vertexNormalsModel[1],wb),c(l.v3.positionWorld,l.vertexNormalsModel[2],xb),vb.multiply(zb).add(Ab),wb.multiply(zb).add(Ab),xb.multiply(zb).add(Ab),yb.addColors(wb,xb).multiplyScalar(.5),P=p(vb,wb,xb,yb),o(H,I,J,K,L,M,0,0,1,0,0,1,P)):(ub.copy(Gb),c(l.centroidModel,l.normalModel,ub),ub.multiply(zb).add(Ab),m.wireframe===!0?j(ub,m.wireframeLinewidth,m.wireframeLinecap,m.wireframeLinejoin):k(ub))):m instanceof e.MeshBasicMaterial||m instanceof e.MeshLambertMaterial||m instanceof e.MeshPhongMaterial?null!==m.map?m.map.mapping instanceof e.UVMapping&&(Q=l.uvs[0],n(H,I,J,K,L,M,Q[f].x,Q[f].y,Q[g].x,Q[g].y,Q[h].x,Q[h].y,m.map)):null!==m.envMap?m.envMap.mapping instanceof e.SphericalReflectionMapping&&(Kb.copy(l.vertexNormalsModel[f]).applyMatrix3(Lb),R=.5*Kb.x+.5,S=.5*Kb.y+.5,Kb.copy(l.vertexNormalsModel[g]).applyMatrix3(Lb),T=.5*Kb.x+.5,U=.5*Kb.y+.5,Kb.copy(l.vertexNormalsModel[h]).applyMatrix3(Lb),V=.5*Kb.x+.5,W=.5*Kb.y+.5,n(H,I,J,K,L,M,R,S,T,U,V,W,m.envMap)):(ub.copy(m.color),m.vertexColors===e.FaceColors&&ub.multiply(l.color),m.wireframe===!0?j(ub,m.wireframeLinewidth,m.wireframeLinecap,m.wireframeLinejoin):k(ub)):m instanceof e.MeshDepthMaterial?(N=D.near,O=D.far,vb.r=vb.g=vb.b=1-z(a.positionScreen.z*a.positionScreen.w,N,O),wb.r=wb.g=wb.b=1-z(b.positionScreen.z*b.positionScreen.w,N,O),xb.r=xb.g=xb.b=1-z(d.positionScreen.z*d.positionScreen.w,N,O),yb.addColors(wb,xb).multiplyScalar(.5),P=p(vb,wb,xb,yb),o(H,I,J,K,L,M,0,0,1,0,0,1,P)):m instanceof e.MeshNormalMaterial&&(m.shading===e.FlatShading?(Kb.copy(l.normalModel).applyMatrix3(Lb),ub.setRGB(Kb.x,Kb.y,Kb.z).multiplyScalar(.5).addScalar(.5),m.wireframe===!0?j(ub,m.wireframeLinewidth,m.wireframeLinecap,m.wireframeLinejoin):k(ub)):m.shading===e.SmoothShading&&(Kb.copy(l.vertexNormalsModel[f]).applyMatrix3(Lb),vb.setRGB(Kb.x,Kb.y,Kb.z).multiplyScalar(.5).addScalar(.5),Kb.copy(l.vertexNormalsModel[g]).applyMatrix3(Lb),wb.setRGB(Kb.x,Kb.y,Kb.z).multiplyScalar(.5).addScalar(.5),Kb.copy(l.vertexNormalsModel[h]).applyMatrix3(Lb),xb.setRGB(Kb.x,Kb.y,Kb.z).multiplyScalar(.5).addScalar(.5),yb.addColors(wb,xb).multiplyScalar(.5),P=p(vb,wb,xb,yb),o(H,I,J,K,L,M,0,0,1,0,0,1,P)))}function i(a,b,c,d,e,f){ib.beginPath(),ib.moveTo(a,b),ib.lineTo(c,d),ib.lineTo(e,f),ib.closePath()}function j(a,b,c,d){t(b),u(c),v(d),w(a.getStyle()),ib.stroke(),Fb.expandByScalar(2*b)}function k(a){x(a.getStyle()),ib.fill()}function l(a){m(a.target)}function m(a){var b=a.wrapS===e.RepeatWrapping,c=a.wrapT===e.RepeatWrapping,d=a.image,f=document.createElement("canvas");f.width=d.width,f.height=d.height;var g=f.getContext("2d");g.setTransform(1,0,0,-1,0,d.height),g.drawImage(d,0,0),Cb[a.id]=ib.createPattern(f,b===!0&&c===!0?"repeat":b===!0&&c===!1?"repeat-x":b===!1&&c===!0?"repeat-y":"no-repeat")}function n(a,b,c,d,f,g,h,i,j,k,n,o,p){if(!(p instanceof e.DataTexture)){p.hasEventListener("update",l)===!1&&(void 0!==p.image&&p.image.width>0&&m(p),p.addEventListener("update",l));var q=Cb[p.id];if(void 0===q)return x("rgba(0,0,0,1)"),void ib.fill();x(q);var r,s,t,u,v,w,y,z,A=p.offset.x/p.repeat.x,B=p.offset.y/p.repeat.y,C=p.image.width*p.repeat.x,D=p.image.height*p.repeat.y;h=(h+A)*C,i=(i+B)*D,j=(j+A)*C,k=(k+B)*D,n=(n+A)*C,o=(o+B)*D,c-=a,d-=b,f-=a,g-=b,j-=h,k-=i,n-=h,o-=i,y=j*o-n*k,0!==y&&(z=1/y,r=(o*c-k*f)*z,s=(o*d-k*g)*z,t=(j*f-n*c)*z,u=(j*g-n*d)*z,v=a-r*h-t*i,w=b-s*h-u*i,ib.save(),ib.transform(r,s,t,u,v,w),ib.fill(),ib.restore())}}function o(a,b,c,d,e,f,g,h,i,j,k,l,m){var n,o,p,q,r,s,t,u,v=m.width-1,w=m.height-1;g*=v,h*=w,i*=v,j*=w,k*=v,l*=w,c-=a,d-=b,e-=a,f-=b,i-=g,j-=h,k-=g,l-=h,t=i*l-k*j,u=1/t,n=(l*c-j*e)*u,o=(l*d-j*f)*u,p=(i*e-k*c)*u,q=(i*f-k*d)*u,r=a-n*g-p*h,s=b-o*g-q*h,ib.save(),ib.transform(n,o,p,q,r,s),ib.clip(),ib.drawImage(m,0,0),ib.restore()}function p(a,b,c,d){return $[0]=255*a.r|0,$[1]=255*a.g|0,$[2]=255*a.b|0,$[4]=255*b.r|0,$[5]=255*b.g|0,$[6]=255*b.b|0,$[8]=255*c.r|0,$[9]=255*c.g|0,$[10]=255*c.b|0,$[12]=255*d.r|0,$[13]=255*d.g|0,$[14]=255*d.b|0,Y.putImageData(Z,0,0),ab.drawImage(X,0,0),_}function q(a,b,c){var d,e=b.x-a.x,f=b.y-a.y,g=e*e+f*f;0!==g&&(d=c/Math.sqrt(g),e*=d,f*=d,b.x+=e,b.y+=f,a.x-=e,a.y-=f)}function r(a){lb!==a&&(ib.globalAlpha=a,lb=a)}function s(a){mb!==a&&(a===e.NormalBlending?ib.globalCompositeOperation="source-over":a===e.AdditiveBlending?ib.globalCompositeOperation="lighter":a===e.SubtractiveBlending&&(ib.globalCompositeOperation="darker"),mb=a)}function t(a){pb!==a&&(ib.lineWidth=a,pb=a)}function u(a){qb!==a&&(ib.lineCap=a,qb=a)}function v(a){rb!==a&&(ib.lineJoin=a,rb=a)}function w(a){nb!==a&&(ib.strokeStyle=a,nb=a)}function x(a){ob!==a&&(ib.fillStyle=a,ob=a)}function y(a,b){(sb!==a||tb!==b)&&(ib.setLineDash([a,b]),sb=a,tb=b)}console.log("THREE.CanvasRenderer",e.REVISION);var z=e.Math.smoothstep;a=a||{};var A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,$,_,ab,bb=this,cb=new e.Projector,db=void 0!==a.canvas?a.canvas:document.createElement("canvas"),eb=db.width,fb=db.height,gb=Math.floor(eb/2),hb=Math.floor(fb/2),ib=db.getContext("2d",{alpha:a.alpha===!0}),jb=new e.Color(0),kb=0,lb=1,mb=0,nb=null,ob=null,pb=null,qb=null,rb=null,sb=null,tb=0,ub=(new e.RenderableVertex,new e.RenderableVertex,new e.Color),vb=new e.Color,wb=new e.Color,xb=new e.Color,yb=new e.Color,zb=new e.Color,Ab=new e.Color,Bb=new e.Color,Cb={},Db=new e.Box2,Eb=new e.Box2,Fb=new e.Box2,Gb=new e.Color,Hb=new e.Color,Ib=new e.Color,Jb=new e.Vector3,Kb=new e.Vector3,Lb=new e.Matrix3,Mb=16;X=document.createElement("canvas"),X.width=X.height=2,Y=X.getContext("2d"),Y.fillStyle="rgba(0,0,0,1)",Y.fillRect(0,0,2,2),Z=Y.getImageData(0,0,2,2),$=Z.data,_=document.createElement("canvas"),_.width=_.height=Mb,ab=_.getContext("2d"),ab.translate(-Mb/2,-Mb/2),ab.scale(Mb,Mb),Mb--,void 0===ib.setLineDash&&(ib.setLineDash=void 0!==ib.mozDash?function(a){ib.mozDash=null!==a[0]?a:null}:function(){}),this.domElement=db,this.devicePixelRatio=void 0!==a.devicePixelRatio?a.devicePixelRatio:void 0!==d.devicePixelRatio?d.devicePixelRatio:1,this.autoClear=!0,this.sortObjects=!0,this.sortElements=!0,this.info={render:{vertices:0,faces:0}},this.supportsVertexTextures=function(){},this.setFaceCulling=function(){},this.setSize=function(a,b,c){eb=a*this.devicePixelRatio,fb=b*this.devicePixelRatio,gb=Math.floor(eb/2),hb=Math.floor(fb/2),db.width=eb,db.height=fb,1!==this.devicePixelRatio&&c!==!1&&(db.style.width=a+"px",db.style.height=b+"px"),Db.min.set(-gb,-hb),Db.max.set(gb,hb),Eb.min.set(-gb,-hb),Eb.max.set(gb,hb),lb=1,mb=0,nb=null,ob=null,pb=null,qb=null,rb=null},this.setClearColor=function(a,b){jb.set(a),kb=void 0!==b?b:1,Eb.min.set(-gb,-hb),Eb.max.set(gb,hb)},this.setClearColorHex=function(a,b){console.warn("DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead."),this.setClearColor(a,b)},this.getMaxAnisotropy=function(){return 0},this.clear=function(){ib.setTransform(1,0,0,-1,gb,hb),Eb.empty()===!1&&(Eb.intersect(Db),Eb.expandByScalar(2),1>kb&&ib.clearRect(0|Eb.min.x,0|Eb.min.y,Eb.max.x-Eb.min.x|0,Eb.max.y-Eb.min.y|0),kb>0&&(s(e.NormalBlending),r(1),x("rgba("+Math.floor(255*jb.r)+","+Math.floor(255*jb.g)+","+Math.floor(255*jb.b)+","+kb+")"),ib.fillRect(0|Eb.min.x,0|Eb.min.y,Eb.max.x-Eb.min.x|0,Eb.max.y-Eb.min.y|0)),Eb.makeEmpty())},this.clearColor=function(){},this.clearDepth=function(){},this.clearStencil=function(){},this.render=function(a,c){if(c instanceof e.Camera==!1)return void console.error("THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.");this.autoClear===!0&&this.clear(),ib.setTransform(1,0,0,-1,gb,hb),bb.info.render.vertices=0,bb.info.render.faces=0,A=cb.projectScene(a,c,this.sortObjects,this.sortElements),B=A.elements,C=A.lights,D=c,Lb.getNormalMatrix(c.matrixWorldInverse),b();for(var d=0,i=B.length;i>d;d++){var j=B[d],k=j.material;if(void 0!==k&&k.visible!==!1){if(Fb.makeEmpty(),j instanceof e.RenderableSprite)E=j,E.x*=gb,E.y*=hb,f(E,j,k);else if(j instanceof e.RenderableLine)E=j.v1,F=j.v2,E.positionScreen.x*=gb,E.positionScreen.y*=hb,F.positionScreen.x*=gb,F.positionScreen.y*=hb,Fb.setFromPoints([E.positionScreen,F.positionScreen]),Db.isIntersectionBox(Fb)===!0&&g(E,F,j,k);else if(j instanceof e.RenderableFace){if(E=j.v1,F=j.v2,G=j.v3,E.positionScreen.z<-1||E.positionScreen.z>1)continue;if(F.positionScreen.z<-1||F.positionScreen.z>1)continue;if(G.positionScreen.z<-1||G.positionScreen.z>1)continue;E.positionScreen.x*=gb,E.positionScreen.y*=hb,F.positionScreen.x*=gb,F.positionScreen.y*=hb,G.positionScreen.x*=gb,G.positionScreen.y*=hb,k.overdraw>0&&(q(E.positionScreen,F.positionScreen,k.overdraw),q(F.positionScreen,G.positionScreen,k.overdraw),q(G.positionScreen,E.positionScreen,k.overdraw)),Fb.setFromPoints([E.positionScreen,F.positionScreen,G.positionScreen]),Db.isIntersectionBox(Fb)===!0&&h(E,F,G,0,1,2,j,k)}Eb.union(Fb)}}ib.setTransform(1,0,0,1,0,0)}},e.ShaderChunk={fog_pars_fragment:["#ifdef USE_FOG","uniform vec3 fogColor;","#ifdef FOG_EXP2","uniform float fogDensity;","#else","uniform float fogNear;","uniform float fogFar;","#endif","#endif"].join("\n"),fog_fragment:["#ifdef USE_FOG","float depth = gl_FragCoord.z / gl_FragCoord.w;","#ifdef FOG_EXP2","const float LOG2 = 1.442695;","float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );","fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );","#else","float fogFactor = smoothstep( fogNear, fogFar, depth );","#endif","gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );","#endif"].join("\n"),envmap_pars_fragment:["#ifdef USE_ENVMAP","uniform float reflectivity;","uniform samplerCube envMap;","uniform float flipEnvMap;","uniform int combine;","#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )","uniform bool useRefract;","uniform float refractionRatio;","#else","varying vec3 vReflect;","#endif","#endif"].join("\n"),envmap_fragment:["#ifdef USE_ENVMAP","vec3 reflectVec;","#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )","vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );","if ( useRefract ) {","reflectVec = refract( cameraToVertex, normal, refractionRatio );","} else { ","reflectVec = reflect( cameraToVertex, normal );","}","#else","reflectVec = vReflect;","#endif","#ifdef DOUBLE_SIDED","float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );","vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );","#else","vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );","#endif","#ifdef GAMMA_INPUT","cubeColor.xyz *= cubeColor.xyz;","#endif","if ( combine == 1 ) {","gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );","} else if ( combine == 2 ) {","gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;","} else {","gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );","}","#endif"].join("\n"),envmap_pars_vertex:["#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )","varying vec3 vReflect;","uniform float refractionRatio;","uniform bool useRefract;","#endif"].join("\n"),worldpos_vertex:["#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )","#ifdef USE_SKINNING","vec4 worldPosition = modelMatrix * skinned;","#endif","#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )","vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );","#endif","#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )","vec4 worldPosition = modelMatrix * vec4( position, 1.0 );","#endif","#endif"].join("\n"),envmap_vertex:["#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )","vec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;","worldNormal = normalize( worldNormal );","vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );","if ( useRefract ) {","vReflect = refract( cameraToVertex, worldNormal, refractionRatio );","} else {","vReflect = reflect( cameraToVertex, worldNormal );","}","#endif"].join("\n"),map_particle_pars_fragment:["#ifdef USE_MAP","uniform sampler2D map;","#endif"].join("\n"),map_particle_fragment:["#ifdef USE_MAP","gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );","#endif"].join("\n"),map_pars_vertex:["#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )","varying vec2 vUv;","uniform vec4 offsetRepeat;","#endif"].join("\n"),map_pars_fragment:["#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )","varying vec2 vUv;","#endif","#ifdef USE_MAP","uniform sampler2D map;","#endif"].join("\n"),map_vertex:["#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )","vUv = uv * offsetRepeat.zw + offsetRepeat.xy;","#endif"].join("\n"),map_fragment:["#ifdef USE_MAP","vec4 texelColor = texture2D( map, vUv );","#ifdef GAMMA_INPUT","texelColor.xyz *= texelColor.xyz;","#endif","gl_FragColor = gl_FragColor * texelColor;","#endif"].join("\n"),lightmap_pars_fragment:["#ifdef USE_LIGHTMAP","varying vec2 vUv2;","uniform sampler2D lightMap;","#endif"].join("\n"),lightmap_pars_vertex:["#ifdef USE_LIGHTMAP","varying vec2 vUv2;","#endif"].join("\n"),lightmap_fragment:["#ifdef USE_LIGHTMAP","gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );","#endif"].join("\n"),lightmap_vertex:["#ifdef USE_LIGHTMAP","vUv2 = uv2;","#endif"].join("\n"),bumpmap_pars_fragment:["#ifdef USE_BUMPMAP","uniform sampler2D bumpMap;","uniform float bumpScale;","vec2 dHdxy_fwd() {","vec2 dSTdx = dFdx( vUv );","vec2 dSTdy = dFdy( vUv );","float Hll = bumpScale * texture2D( bumpMap, vUv ).x;","float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;","float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;","return vec2( dBx, dBy );","}","vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {","vec3 vSigmaX = dFdx( surf_pos );","vec3 vSigmaY = dFdy( surf_pos );","vec3 vN = surf_norm;","vec3 R1 = cross( vSigmaY, vN );","vec3 R2 = cross( vN, vSigmaX );","float fDet = dot( vSigmaX, R1 );","vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );","return normalize( abs( fDet ) * surf_norm - vGrad );","}","#endif"].join("\n"),normalmap_pars_fragment:["#ifdef USE_NORMALMAP","uniform sampler2D normalMap;","uniform vec2 normalScale;","vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {","vec3 q0 = dFdx( eye_pos.xyz );","vec3 q1 = dFdy( eye_pos.xyz );","vec2 st0 = dFdx( vUv.st );","vec2 st1 = dFdy( vUv.st );","vec3 S = normalize( q0 * st1.t - q1 * st0.t );","vec3 T = normalize( -q0 * st1.s + q1 * st0.s );","vec3 N = normalize( surf_norm );","vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;","mapN.xy = normalScale * mapN.xy;","mat3 tsn = mat3( S, T, N );","return normalize( tsn * mapN );","}","#endif"].join("\n"),specularmap_pars_fragment:["#ifdef USE_SPECULARMAP","uniform sampler2D specularMap;","#endif"].join("\n"),specularmap_fragment:["float specularStrength;","#ifdef USE_SPECULARMAP","vec4 texelSpecular = texture2D( specularMap, vUv );","specularStrength = texelSpecular.r;","#else","specularStrength = 1.0;","#endif"].join("\n"),lights_lambert_pars_vertex:["uniform vec3 ambient;","uniform vec3 diffuse;","uniform vec3 emissive;","uniform vec3 ambientLightColor;","#if MAX_DIR_LIGHTS > 0","uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];","uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];","#endif","#if MAX_HEMI_LIGHTS > 0","uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];","#endif","#if MAX_POINT_LIGHTS > 0","uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];","uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];","uniform float pointLightDistance[ MAX_POINT_LIGHTS ];","#endif","#if MAX_SPOT_LIGHTS > 0","uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];","uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];","uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];","uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];","#endif","#ifdef WRAP_AROUND","uniform vec3 wrapRGB;","#endif"].join("\n"),lights_lambert_vertex:["vLightFront = vec3( 0.0 );","#ifdef DOUBLE_SIDED","vLightBack = vec3( 0.0 );","#endif","transformedNormal = normalize( transformedNormal );","#if MAX_DIR_LIGHTS > 0","for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {","vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );","vec3 dirVector = normalize( lDirection.xyz );","float dotProduct = dot( transformedNormal, dirVector );","vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );","#ifdef DOUBLE_SIDED","vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );","#ifdef WRAP_AROUND","vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );","#endif","#endif","#ifdef WRAP_AROUND","vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );","directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );","#ifdef DOUBLE_SIDED","directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );","#endif","#endif","vLightFront += directionalLightColor[ i ] * directionalLightWeighting;","#ifdef DOUBLE_SIDED","vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;","#endif","}","#endif","#if MAX_POINT_LIGHTS > 0","for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );","vec3 lVector = lPosition.xyz - mvPosition.xyz;","float lDistance = 1.0;","if ( pointLightDistance[ i ] > 0.0 )","lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );","lVector = normalize( lVector );","float dotProduct = dot( transformedNormal, lVector );","vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );","#ifdef DOUBLE_SIDED","vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );","#ifdef WRAP_AROUND","vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );","#endif","#endif","#ifdef WRAP_AROUND","vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );","pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );","#ifdef DOUBLE_SIDED","pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );","#endif","#endif","vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;","#ifdef DOUBLE_SIDED","vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;","#endif","}","#endif","#if MAX_SPOT_LIGHTS > 0","for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );","vec3 lVector = lPosition.xyz - mvPosition.xyz;","float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );","if ( spotEffect > spotLightAngleCos[ i ] ) {","spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );","float lDistance = 1.0;","if ( spotLightDistance[ i ] > 0.0 )","lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );","lVector = normalize( lVector );","float dotProduct = dot( transformedNormal, lVector );","vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );","#ifdef DOUBLE_SIDED","vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );","#ifdef WRAP_AROUND","vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );","#endif","#endif","#ifdef WRAP_AROUND","vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );","spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );","#ifdef DOUBLE_SIDED","spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );","#endif","#endif","vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;","#ifdef DOUBLE_SIDED","vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;","#endif","}","}","#endif","#if MAX_HEMI_LIGHTS > 0","for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {","vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );","vec3 lVector = normalize( lDirection.xyz );","float dotProduct = dot( transformedNormal, lVector );","float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;","float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;","vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );","#ifdef DOUBLE_SIDED","vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );","#endif","}","#endif","vLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;","#ifdef DOUBLE_SIDED","vLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;","#endif"].join("\n"),lights_phong_pars_vertex:["#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )","varying vec3 vWorldPosition;","#endif"].join("\n"),lights_phong_vertex:["#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )","vWorldPosition = worldPosition.xyz;","#endif"].join("\n"),lights_phong_pars_fragment:["uniform vec3 ambientLightColor;","#if MAX_DIR_LIGHTS > 0","uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];","uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];","#endif","#if MAX_HEMI_LIGHTS > 0","uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];","#endif","#if MAX_POINT_LIGHTS > 0","uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];","uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];","uniform float pointLightDistance[ MAX_POINT_LIGHTS ];","#endif","#if MAX_SPOT_LIGHTS > 0","uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];","uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];","uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];","uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];","#endif","#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )","varying vec3 vWorldPosition;","#endif","#ifdef WRAP_AROUND","uniform vec3 wrapRGB;","#endif","varying vec3 vViewPosition;","varying vec3 vNormal;"].join("\n"),lights_phong_fragment:["vec3 normal = normalize( vNormal );","vec3 viewPosition = normalize( vViewPosition );","#ifdef DOUBLE_SIDED","normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );","#endif","#ifdef USE_NORMALMAP","normal = perturbNormal2Arb( -vViewPosition, normal );","#elif defined( USE_BUMPMAP )","normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );","#endif","#if MAX_POINT_LIGHTS > 0","vec3 pointDiffuse = vec3( 0.0 );","vec3 pointSpecular = vec3( 0.0 );","for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );","vec3 lVector = lPosition.xyz + vViewPosition.xyz;","float lDistance = 1.0;","if ( pointLightDistance[ i ] > 0.0 )","lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );","lVector = normalize( lVector );","float dotProduct = dot( normal, lVector );","#ifdef WRAP_AROUND","float pointDiffuseWeightFull = max( dotProduct, 0.0 );","float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );","vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );","#else","float pointDiffuseWeight = max( dotProduct, 0.0 );","#endif","pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;","vec3 pointHalfVector = normalize( lVector + viewPosition );","float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );","float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );","pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;","}","#endif","#if MAX_SPOT_LIGHTS > 0","vec3 spotDiffuse = vec3( 0.0 );","vec3 spotSpecular = vec3( 0.0 );","for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );","vec3 lVector = lPosition.xyz + vViewPosition.xyz;","float lDistance = 1.0;","if ( spotLightDistance[ i ] > 0.0 )","lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );","lVector = normalize( lVector );","float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );","if ( spotEffect > spotLightAngleCos[ i ] ) {","spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );","float dotProduct = dot( normal, lVector );","#ifdef WRAP_AROUND","float spotDiffuseWeightFull = max( dotProduct, 0.0 );","float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );","vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );","#else","float spotDiffuseWeight = max( dotProduct, 0.0 );","#endif","spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;","vec3 spotHalfVector = normalize( lVector + viewPosition );","float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );","float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );","spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;","}","}","#endif","#if MAX_DIR_LIGHTS > 0","vec3 dirDiffuse = vec3( 0.0 );","vec3 dirSpecular = vec3( 0.0 );","for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {","vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );","vec3 dirVector = normalize( lDirection.xyz );","float dotProduct = dot( normal, dirVector );","#ifdef WRAP_AROUND","float dirDiffuseWeightFull = max( dotProduct, 0.0 );","float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );","vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );","#else","float dirDiffuseWeight = max( dotProduct, 0.0 );","#endif","dirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;","vec3 dirHalfVector = normalize( dirVector + viewPosition );","float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );","float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );","dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;","}","#endif","#if MAX_HEMI_LIGHTS > 0","vec3 hemiDiffuse = vec3( 0.0 );","vec3 hemiSpecular = vec3( 0.0 );","for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {","vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );","vec3 lVector = normalize( lDirection.xyz );","float dotProduct = dot( normal, lVector );","float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;","vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );","hemiDiffuse += diffuse * hemiColor;","vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );","float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;","float hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );","vec3 lVectorGround = -lVector;","vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );","float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;","float hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );","float dotProductGround = dot( normal, lVectorGround );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );","vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );","hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );","}","#endif","vec3 totalDiffuse = vec3( 0.0 );","vec3 totalSpecular = vec3( 0.0 );","#if MAX_DIR_LIGHTS > 0","totalDiffuse += dirDiffuse;","totalSpecular += dirSpecular;","#endif","#if MAX_HEMI_LIGHTS > 0","totalDiffuse += hemiDiffuse;","totalSpecular += hemiSpecular;","#endif","#if MAX_POINT_LIGHTS > 0","totalDiffuse += pointDiffuse;","totalSpecular += pointSpecular;","#endif","#if MAX_SPOT_LIGHTS > 0","totalDiffuse += spotDiffuse;","totalSpecular += spotSpecular;","#endif","#ifdef METAL","gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );","#else","gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;","#endif"].join("\n"),color_pars_fragment:["#ifdef USE_COLOR","varying vec3 vColor;","#endif"].join("\n"),color_fragment:["#ifdef USE_COLOR","gl_FragColor = gl_FragColor * vec4( vColor, 1.0 );","#endif"].join("\n"),color_pars_vertex:["#ifdef USE_COLOR","varying vec3 vColor;","#endif"].join("\n"),color_vertex:["#ifdef USE_COLOR","#ifdef GAMMA_INPUT","vColor = color * color;","#else","vColor = color;","#endif","#endif"].join("\n"),skinning_pars_vertex:["#ifdef USE_SKINNING","#ifdef BONE_TEXTURE","uniform sampler2D boneTexture;","uniform int boneTextureWidth;","uniform int boneTextureHeight;","mat4 getBoneMatrix( const in float i ) {","float j = i * 4.0;","float x = mod( j, float( boneTextureWidth ) );","float y = floor( j / float( boneTextureWidth ) );","float dx = 1.0 / float( boneTextureWidth );","float dy = 1.0 / float( boneTextureHeight );","y = dy * ( y + 0.5 );","vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );","vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );","vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );","vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );","mat4 bone = mat4( v1, v2, v3, v4 );","return bone;","}","#else","uniform mat4 boneGlobalMatrices[ MAX_BONES ];","mat4 getBoneMatrix( const in float i ) {","mat4 bone = boneGlobalMatrices[ int(i) ];","return bone;","}","#endif","#endif"].join("\n"),skinbase_vertex:["#ifdef USE_SKINNING","mat4 boneMatX = getBoneMatrix( skinIndex.x );","mat4 boneMatY = getBoneMatrix( skinIndex.y );","mat4 boneMatZ = getBoneMatrix( skinIndex.z );","mat4 boneMatW = getBoneMatrix( skinIndex.w );","#endif"].join("\n"),skinning_vertex:["#ifdef USE_SKINNING","#ifdef USE_MORPHTARGETS","vec4 skinVertex = vec4( morphed, 1.0 );","#else","vec4 skinVertex = vec4( position, 1.0 );","#endif","vec4 skinned = boneMatX * skinVertex * skinWeight.x;","skinned += boneMatY * skinVertex * skinWeight.y;","skinned += boneMatZ * skinVertex * skinWeight.z;","skinned += boneMatW * skinVertex * skinWeight.w;","#endif"].join("\n"),morphtarget_pars_vertex:["#ifdef USE_MORPHTARGETS","#ifndef USE_MORPHNORMALS","uniform float morphTargetInfluences[ 8 ];","#else","uniform float morphTargetInfluences[ 4 ];","#endif","#endif"].join("\n"),morphtarget_vertex:["#ifdef USE_MORPHTARGETS","vec3 morphed = vec3( 0.0 );","morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];","morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];","morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];","morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];","#ifndef USE_MORPHNORMALS","morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];","morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];","morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];","morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];","#endif","morphed += position;","#endif"].join("\n"),default_vertex:["vec4 mvPosition;","#ifdef USE_SKINNING","mvPosition = modelViewMatrix * skinned;","#endif","#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )","mvPosition = modelViewMatrix * vec4( morphed, 1.0 );","#endif","#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )","mvPosition = modelViewMatrix * vec4( position, 1.0 );","#endif","gl_Position = projectionMatrix * mvPosition;"].join("\n"),morphnormal_vertex:["#ifdef USE_MORPHNORMALS","vec3 morphedNormal = vec3( 0.0 );","morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];","morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];","morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];","morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];","morphedNormal += normal;","#endif"].join("\n"),skinnormal_vertex:["#ifdef USE_SKINNING","mat4 skinMatrix = skinWeight.x * boneMatX;","skinMatrix += skinWeight.y * boneMatY;","#ifdef USE_MORPHNORMALS","vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );","#else","vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );","#endif","#endif"].join("\n"),defaultnormal_vertex:["vec3 objectNormal;","#ifdef USE_SKINNING","objectNormal = skinnedNormal.xyz;","#endif","#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )","objectNormal = morphedNormal;","#endif","#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )","objectNormal = normal;","#endif","#ifdef FLIP_SIDED","objectNormal = -objectNormal;","#endif","vec3 transformedNormal = normalMatrix * objectNormal;"].join("\n"),shadowmap_pars_fragment:["#ifdef USE_SHADOWMAP","uniform sampler2D shadowMap[ MAX_SHADOWS ];","uniform vec2 shadowMapSize[ MAX_SHADOWS ];","uniform float shadowDarkness[ MAX_SHADOWS ];","uniform float shadowBias[ MAX_SHADOWS ];","varying vec4 vShadowCoord[ MAX_SHADOWS ];","float unpackDepth( const in vec4 rgba_depth ) {","const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );","float depth = dot( rgba_depth, bit_shift );","return depth;","}","#endif"].join("\n"),shadowmap_fragment:["#ifdef USE_SHADOWMAP","#ifdef SHADOWMAP_DEBUG","vec3 frustumColors[3];","frustumColors[0] = vec3( 1.0, 0.5, 0.0 );","frustumColors[1] = vec3( 0.0, 1.0, 0.8 );","frustumColors[2] = vec3( 0.0, 0.5, 1.0 );","#endif","#ifdef SHADOWMAP_CASCADE","int inFrustumCount = 0;","#endif","float fDepth;","vec3 shadowColor = vec3( 1.0 );","for( int i = 0; i < MAX_SHADOWS; i ++ ) {","vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;","bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );","bool inFrustum = all( inFrustumVec );","#ifdef SHADOWMAP_CASCADE","inFrustumCount += int( inFrustum );","bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );","#else","bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );","#endif","bool frustumTest = all( frustumTestVec );","if ( frustumTest ) {","shadowCoord.z += shadowBias[ i ];","#if defined( SHADOWMAP_TYPE_PCF )","float shadow = 0.0;","const float shadowDelta = 1.0 / 9.0;","float xPixelOffset = 1.0 / shadowMapSize[ i ].x;","float yPixelOffset = 1.0 / shadowMapSize[ i ].y;","float dx0 = -1.25 * xPixelOffset;","float dy0 = -1.25 * yPixelOffset;","float dx1 = 1.25 * xPixelOffset;","float dy1 = 1.25 * yPixelOffset;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );","#elif defined( SHADOWMAP_TYPE_PCF_SOFT )","float shadow = 0.0;","float xPixelOffset = 1.0 / shadowMapSize[ i ].x;","float yPixelOffset = 1.0 / shadowMapSize[ i ].y;","float dx0 = -1.0 * xPixelOffset;","float dy0 = -1.0 * yPixelOffset;","float dx1 = 1.0 * xPixelOffset;","float dy1 = 1.0 * yPixelOffset;","mat3 shadowKernel;","mat3 depthKernel;","depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );","depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );","depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );","depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );","depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );","depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );","depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );","depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );","depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );","vec3 shadowZ = vec3( shadowCoord.z );","shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));","shadowKernel[0] *= vec3(0.25);","shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));","shadowKernel[1] *= vec3(0.25);","shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));","shadowKernel[2] *= vec3(0.25);","vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );","shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );","shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );","vec4 shadowValues;","shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );","shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );","shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );","shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );","shadow = dot( shadowValues, vec4( 1.0 ) );","shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );","#else","vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );","float fDepth = unpackDepth( rgbaDepth );","if ( fDepth < shadowCoord.z )","shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );","#endif","}","#ifdef SHADOWMAP_DEBUG","#ifdef SHADOWMAP_CASCADE","if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];","#else","if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];","#endif","#endif","}","#ifdef GAMMA_OUTPUT","shadowColor *= shadowColor;","#endif","gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;","#endif"].join("\n"),shadowmap_pars_vertex:["#ifdef USE_SHADOWMAP","varying vec4 vShadowCoord[ MAX_SHADOWS ];","uniform mat4 shadowMatrix[ MAX_SHADOWS ];","#endif"].join("\n"),shadowmap_vertex:["#ifdef USE_SHADOWMAP","for( int i = 0; i < MAX_SHADOWS; i ++ ) {","vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;","}","#endif"].join("\n"),alphatest_fragment:["#ifdef ALPHATEST","if ( gl_FragColor.a < ALPHATEST ) discard;","#endif"].join("\n"),linear_to_gamma_fragment:["#ifdef GAMMA_OUTPUT","gl_FragColor.xyz = sqrt( gl_FragColor.xyz );","#endif"].join("\n")},e.UniformsUtils={merge:function(a){var b,c,d,e={}; -for(b=0;b dashSize ) {","discard;","}","gl_FragColor = vec4( diffuse, opacity );",e.ShaderChunk.color_fragment,e.ShaderChunk.fog_fragment,"}"].join("\n")},depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2e3},opacity:{type:"f",value:1}},vertexShader:["void main() {","gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );","}"].join("\n"),fragmentShader:["uniform float mNear;","uniform float mFar;","uniform float opacity;","void main() {","float depth = gl_FragCoord.z / gl_FragCoord.w;","float color = 1.0 - smoothstep( mNear, mFar, depth );","gl_FragColor = vec4( vec3( color ), opacity );","}"].join("\n")},normal:{uniforms:{opacity:{type:"f",value:1}},vertexShader:["varying vec3 vNormal;",e.ShaderChunk.morphtarget_pars_vertex,"void main() {","vNormal = normalize( normalMatrix * normal );",e.ShaderChunk.morphtarget_vertex,e.ShaderChunk.default_vertex,"}"].join("\n"),fragmentShader:["uniform float opacity;","varying vec3 vNormal;","void main() {","gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );","}"].join("\n")},normalmap:{uniforms:e.UniformsUtils.merge([e.UniformsLib.fog,e.UniformsLib.lights,e.UniformsLib.shadowmap,{enableAO:{type:"i",value:0},enableDiffuse:{type:"i",value:0},enableSpecular:{type:"i",value:0},enableReflection:{type:"i",value:0},enableDisplacement:{type:"i",value:0},tDisplacement:{type:"t",value:null},tDiffuse:{type:"t",value:null},tCube:{type:"t",value:null},tNormal:{type:"t",value:null},tSpecular:{type:"t",value:null},tAO:{type:"t",value:null},uNormalScale:{type:"v2",value:new e.Vector2(1,1)},uDisplacementBias:{type:"f",value:0},uDisplacementScale:{type:"f",value:1},diffuse:{type:"c",value:new e.Color(16777215)},specular:{type:"c",value:new e.Color(1118481)},ambient:{type:"c",value:new e.Color(16777215)},shininess:{type:"f",value:30},opacity:{type:"f",value:1},useRefract:{type:"i",value:0},refractionRatio:{type:"f",value:.98},reflectivity:{type:"f",value:.5},uOffset:{type:"v2",value:new e.Vector2(0,0)},uRepeat:{type:"v2",value:new e.Vector2(1,1)},wrapRGB:{type:"v3",value:new e.Vector3(1,1,1)}}]),fragmentShader:["uniform vec3 ambient;","uniform vec3 diffuse;","uniform vec3 specular;","uniform float shininess;","uniform float opacity;","uniform bool enableDiffuse;","uniform bool enableSpecular;","uniform bool enableAO;","uniform bool enableReflection;","uniform sampler2D tDiffuse;","uniform sampler2D tNormal;","uniform sampler2D tSpecular;","uniform sampler2D tAO;","uniform samplerCube tCube;","uniform vec2 uNormalScale;","uniform bool useRefract;","uniform float refractionRatio;","uniform float reflectivity;","varying vec3 vTangent;","varying vec3 vBinormal;","varying vec3 vNormal;","varying vec2 vUv;","uniform vec3 ambientLightColor;","#if MAX_DIR_LIGHTS > 0","uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];","uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];","#endif","#if MAX_HEMI_LIGHTS > 0","uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];","#endif","#if MAX_POINT_LIGHTS > 0","uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];","uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];","uniform float pointLightDistance[ MAX_POINT_LIGHTS ];","#endif","#if MAX_SPOT_LIGHTS > 0","uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];","uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];","uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];","uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];","#endif","#ifdef WRAP_AROUND","uniform vec3 wrapRGB;","#endif","varying vec3 vWorldPosition;","varying vec3 vViewPosition;",e.ShaderChunk.shadowmap_pars_fragment,e.ShaderChunk.fog_pars_fragment,"void main() {","gl_FragColor = vec4( vec3( 1.0 ), opacity );","vec3 specularTex = vec3( 1.0 );","vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;","normalTex.xy *= uNormalScale;","normalTex = normalize( normalTex );","if( enableDiffuse ) {","#ifdef GAMMA_INPUT","vec4 texelColor = texture2D( tDiffuse, vUv );","texelColor.xyz *= texelColor.xyz;","gl_FragColor = gl_FragColor * texelColor;","#else","gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );","#endif","}","if( enableAO ) {","#ifdef GAMMA_INPUT","vec4 aoColor = texture2D( tAO, vUv );","aoColor.xyz *= aoColor.xyz;","gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;","#else","gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;","#endif","}","if( enableSpecular )","specularTex = texture2D( tSpecular, vUv ).xyz;","mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );","vec3 finalNormal = tsb * normalTex;","#ifdef FLIP_SIDED","finalNormal = -finalNormal;","#endif","vec3 normal = normalize( finalNormal );","vec3 viewPosition = normalize( vViewPosition );","#if MAX_POINT_LIGHTS > 0","vec3 pointDiffuse = vec3( 0.0 );","vec3 pointSpecular = vec3( 0.0 );","for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );","vec3 pointVector = lPosition.xyz + vViewPosition.xyz;","float pointDistance = 1.0;","if ( pointLightDistance[ i ] > 0.0 )","pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );","pointVector = normalize( pointVector );","#ifdef WRAP_AROUND","float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );","float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );","vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );","#else","float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );","#endif","pointDiffuse += pointDistance * pointLightColor[ i ] * diffuse * pointDiffuseWeight;","vec3 pointHalfVector = normalize( pointVector + viewPosition );","float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );","float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );","pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;","}","#endif","#if MAX_SPOT_LIGHTS > 0","vec3 spotDiffuse = vec3( 0.0 );","vec3 spotSpecular = vec3( 0.0 );","for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );","vec3 spotVector = lPosition.xyz + vViewPosition.xyz;","float spotDistance = 1.0;","if ( spotLightDistance[ i ] > 0.0 )","spotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );","spotVector = normalize( spotVector );","float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );","if ( spotEffect > spotLightAngleCos[ i ] ) {","spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );","#ifdef WRAP_AROUND","float spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );","float spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );","vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );","#else","float spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );","#endif","spotDiffuse += spotDistance * spotLightColor[ i ] * diffuse * spotDiffuseWeight * spotEffect;","vec3 spotHalfVector = normalize( spotVector + viewPosition );","float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );","float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, shininess ), 0.0 );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );","spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;","}","}","#endif","#if MAX_DIR_LIGHTS > 0","vec3 dirDiffuse = vec3( 0.0 );","vec3 dirSpecular = vec3( 0.0 );","for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {","vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );","vec3 dirVector = normalize( lDirection.xyz );","#ifdef WRAP_AROUND","float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );","float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );","vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );","#else","float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );","#endif","dirDiffuse += directionalLightColor[ i ] * diffuse * dirDiffuseWeight;","vec3 dirHalfVector = normalize( dirVector + viewPosition );","float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );","float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, shininess ), 0.0 );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );","dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;","}","#endif","#if MAX_HEMI_LIGHTS > 0","vec3 hemiDiffuse = vec3( 0.0 );","vec3 hemiSpecular = vec3( 0.0 );","for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {","vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );","vec3 lVector = normalize( lDirection.xyz );","float dotProduct = dot( normal, lVector );","float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;","vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );","hemiDiffuse += diffuse * hemiColor;","vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );","float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;","float hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );","vec3 lVectorGround = -lVector;","vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );","float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;","float hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );","float dotProductGround = dot( normal, lVectorGround );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );","vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );","hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );","}","#endif","vec3 totalDiffuse = vec3( 0.0 );","vec3 totalSpecular = vec3( 0.0 );","#if MAX_DIR_LIGHTS > 0","totalDiffuse += dirDiffuse;","totalSpecular += dirSpecular;","#endif","#if MAX_HEMI_LIGHTS > 0","totalDiffuse += hemiDiffuse;","totalSpecular += hemiSpecular;","#endif","#if MAX_POINT_LIGHTS > 0","totalDiffuse += pointDiffuse;","totalSpecular += pointSpecular;","#endif","#if MAX_SPOT_LIGHTS > 0","totalDiffuse += spotDiffuse;","totalSpecular += spotSpecular;","#endif","#ifdef METAL","gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient + totalSpecular );","#else","gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient ) + totalSpecular;","#endif","if ( enableReflection ) {","vec3 vReflect;","vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );","if ( useRefract ) {","vReflect = refract( cameraToVertex, normal, refractionRatio );","} else {","vReflect = reflect( cameraToVertex, normal );","}","vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );","#ifdef GAMMA_INPUT","cubeColor.xyz *= cubeColor.xyz;","#endif","gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * reflectivity );","}",e.ShaderChunk.shadowmap_fragment,e.ShaderChunk.linear_to_gamma_fragment,e.ShaderChunk.fog_fragment,"}"].join("\n"),vertexShader:["attribute vec4 tangent;","uniform vec2 uOffset;","uniform vec2 uRepeat;","uniform bool enableDisplacement;","#ifdef VERTEX_TEXTURES","uniform sampler2D tDisplacement;","uniform float uDisplacementScale;","uniform float uDisplacementBias;","#endif","varying vec3 vTangent;","varying vec3 vBinormal;","varying vec3 vNormal;","varying vec2 vUv;","varying vec3 vWorldPosition;","varying vec3 vViewPosition;",e.ShaderChunk.skinning_pars_vertex,e.ShaderChunk.shadowmap_pars_vertex,"void main() {",e.ShaderChunk.skinbase_vertex,e.ShaderChunk.skinnormal_vertex,"#ifdef USE_SKINNING","vNormal = normalize( normalMatrix * skinnedNormal.xyz );","vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );","vTangent = normalize( normalMatrix * skinnedTangent.xyz );","#else","vNormal = normalize( normalMatrix * normal );","vTangent = normalize( normalMatrix * tangent.xyz );","#endif","vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );","vUv = uv * uRepeat + uOffset;","vec3 displacedPosition;","#ifdef VERTEX_TEXTURES","if ( enableDisplacement ) {","vec3 dv = texture2D( tDisplacement, uv ).xyz;","float df = uDisplacementScale * dv.x + uDisplacementBias;","displacedPosition = position + normalize( normal ) * df;","} else {","#ifdef USE_SKINNING","vec4 skinVertex = vec4( position, 1.0 );","vec4 skinned = boneMatX * skinVertex * skinWeight.x;","skinned += boneMatY * skinVertex * skinWeight.y;","displacedPosition = skinned.xyz;","#else","displacedPosition = position;","#endif","}","#else","#ifdef USE_SKINNING","vec4 skinVertex = vec4( position, 1.0 );","vec4 skinned = boneMatX * skinVertex * skinWeight.x;","skinned += boneMatY * skinVertex * skinWeight.y;","displacedPosition = skinned.xyz;","#else","displacedPosition = position;","#endif","#endif","vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );","vec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );","gl_Position = projectionMatrix * mvPosition;","vWorldPosition = worldPosition.xyz;","vViewPosition = -mvPosition.xyz;","#ifdef USE_SHADOWMAP","for( int i = 0; i < MAX_SHADOWS; i ++ ) {","vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;","}","#endif","}"].join("\n")},cube:{uniforms:{tCube:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:["varying vec3 vWorldPosition;","void main() {","vec4 worldPosition = modelMatrix * vec4( position, 1.0 );","vWorldPosition = worldPosition.xyz;","gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );","}"].join("\n"),fragmentShader:["uniform samplerCube tCube;","uniform float tFlip;","varying vec3 vWorldPosition;","void main() {","gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );","}"].join("\n")},depthRGBA:{uniforms:{},vertexShader:[e.ShaderChunk.morphtarget_pars_vertex,e.ShaderChunk.skinning_pars_vertex,"void main() {",e.ShaderChunk.skinbase_vertex,e.ShaderChunk.morphtarget_vertex,e.ShaderChunk.skinning_vertex,e.ShaderChunk.default_vertex,"}"].join("\n"),fragmentShader:["vec4 pack_depth( const in float depth ) {","const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );","const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );","vec4 res = fract( depth * bit_shift );","res -= res.xxyz * bit_mask;","return res;","}","void main() {","gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );","}"].join("\n")}},e.WebGLRenderer=function(a){function b(a){a.__webglVertexBuffer=Kb.createBuffer(),a.__webglColorBuffer=Kb.createBuffer(),Qb.info.memory.geometries++}function c(a){a.__webglVertexBuffer=Kb.createBuffer(),a.__webglColorBuffer=Kb.createBuffer(),a.__webglLineDistanceBuffer=Kb.createBuffer(),Qb.info.memory.geometries++}function f(a){a.__webglVertexBuffer=Kb.createBuffer(),a.__webglNormalBuffer=Kb.createBuffer(),a.__webglTangentBuffer=Kb.createBuffer(),a.__webglColorBuffer=Kb.createBuffer(),a.__webglUVBuffer=Kb.createBuffer(),a.__webglUV2Buffer=Kb.createBuffer(),a.__webglSkinIndicesBuffer=Kb.createBuffer(),a.__webglSkinWeightsBuffer=Kb.createBuffer(),a.__webglFaceBuffer=Kb.createBuffer(),a.__webglLineBuffer=Kb.createBuffer();var b,c;if(a.numMorphTargets)for(a.__webglMorphTargetsBuffers=[],b=0,c=a.numMorphTargets;c>b;b++)a.__webglMorphTargetsBuffers.push(Kb.createBuffer());if(a.numMorphNormals)for(a.__webglMorphNormalsBuffers=[],b=0,c=a.numMorphNormals;c>b;b++)a.__webglMorphNormalsBuffers.push(Kb.createBuffer());Qb.info.memory.geometries++}function g(a,b){var c=a.vertices.length,d=b.material;if(d.attributes){void 0===a.__webglCustomAttributesList&&(a.__webglCustomAttributesList=[]);for(var e in d.attributes){var f=d.attributes[e];if(!f.__webglInitialized||f.createUniqueBuffers){f.__webglInitialized=!0;var g=1;"v2"===f.type?g=2:"v3"===f.type?g=3:"v4"===f.type?g=4:"c"===f.type&&(g=3),f.size=g,f.array=new Float32Array(c*g),f.buffer=Kb.createBuffer(),f.buffer.belongsToAttribute=e,f.needsUpdate=!0}a.__webglCustomAttributesList.push(f)}}}function h(a,b){var c=a.vertices.length;a.__vertexArray=new Float32Array(3*c),a.__colorArray=new Float32Array(3*c),a.__sortArray=[],a.__webglParticleCount=c,g(a,b)}function i(a,b){var c=a.vertices.length;a.__vertexArray=new Float32Array(3*c),a.__colorArray=new Float32Array(3*c),a.__lineDistanceArray=new Float32Array(1*c),a.__webglLineCount=c,g(a,b)}function j(a,b){var c=b.geometry,d=a.faces3,e=3*d.length,f=1*d.length,g=3*d.length,h=k(b,a),i=o(h),j=m(h),l=n(h);a.__vertexArray=new Float32Array(3*e),j&&(a.__normalArray=new Float32Array(3*e)),c.hasTangents&&(a.__tangentArray=new Float32Array(4*e)),l&&(a.__colorArray=new Float32Array(3*e)),i&&(c.faceVertexUvs.length>0&&(a.__uvArray=new Float32Array(2*e)),c.faceVertexUvs.length>1&&(a.__uv2Array=new Float32Array(2*e))),b.geometry.skinWeights.length&&b.geometry.skinIndices.length&&(a.__skinIndexArray=new Float32Array(4*e),a.__skinWeightArray=new Float32Array(4*e)),a.__faceArray=new Uint16Array(3*f),a.__lineArray=new Uint16Array(2*g);var p,q;if(a.numMorphTargets)for(a.__morphTargetsArrays=[],p=0,q=a.numMorphTargets;q>p;p++)a.__morphTargetsArrays.push(new Float32Array(3*e));if(a.numMorphNormals)for(a.__morphNormalsArrays=[],p=0,q=a.numMorphNormals;q>p;p++)a.__morphNormalsArrays.push(new Float32Array(3*e));if(a.__webglFaceCount=3*f,a.__webglLineCount=2*g,h.attributes){void 0===a.__webglCustomAttributesList&&(a.__webglCustomAttributesList=[]);for(var r in h.attributes){var s=h.attributes[r],t={};for(var u in s)t[u]=s[u];if(!t.__webglInitialized||t.createUniqueBuffers){t.__webglInitialized=!0;var v=1;"v2"===t.type?v=2:"v3"===t.type?v=3:"v4"===t.type?v=4:"c"===t.type&&(v=3),t.size=v,t.array=new Float32Array(e*v),t.buffer=Kb.createBuffer(),t.buffer.belongsToAttribute=r,s.needsUpdate=!0,t.__original=s}a.__webglCustomAttributesList.push(t)}}a.__inittedArrays=!0}function k(a,b){return a.material instanceof e.MeshFaceMaterial?a.material.materials[b.materialIndex]:a.material}function l(a){return a&&void 0!==a.shading&&a.shading===e.SmoothShading}function m(a){return a instanceof e.MeshBasicMaterial&&!a.envMap||a instanceof e.MeshDepthMaterial?!1:l(a)?e.SmoothShading:e.FlatShading}function n(a){return a.vertexColors?a.vertexColors:!1}function o(a){return a.map||a.lightMap||a.bumpMap||a.normalMap||a.specularMap||a instanceof e.ShaderMaterial?!0:!1}function p(a){var b,c,d;for(b in a.attributes)d="index"===b?Kb.ELEMENT_ARRAY_BUFFER:Kb.ARRAY_BUFFER,c=a.attributes[b],c.buffer=Kb.createBuffer(),Kb.bindBuffer(d,c.buffer),Kb.bufferData(d,c.array,Kb.STATIC_DRAW)}function q(a,b,c){var d,e,f,g,h,i,j,k,l,m,n,o,p=a.vertices,q=p.length,r=a.colors,s=r.length,t=a.__vertexArray,u=a.__colorArray,v=a.__sortArray,w=a.verticesNeedUpdate,x=(a.elementsNeedUpdate,a.colorsNeedUpdate),y=a.__webglCustomAttributesList;if(c.sortParticles){for(sc.copy(rc),sc.multiply(c.matrixWorld),d=0;q>d;d++)f=p[d],tc.copy(f),tc.applyProjection(sc),v[d]=[tc.z,d];for(v.sort(z),d=0;q>d;d++)f=p[v[d][1]],g=3*d,t[g]=f.x,t[g+1]=f.y,t[g+2]=f.z;for(e=0;s>e;e++)g=3*e,i=r[v[e][1]],u[g]=i.r,u[g+1]=i.g,u[g+2]=i.b;if(y)for(j=0,k=y.length;k>j;j++)if(o=y[j],void 0===o.boundTo||"vertices"===o.boundTo)if(g=0,m=o.value.length,1===o.size)for(l=0;m>l;l++)h=v[l][1],o.array[l]=o.value[h];else if(2===o.size)for(l=0;m>l;l++)h=v[l][1],n=o.value[h],o.array[g]=n.x,o.array[g+1]=n.y,g+=2;else if(3===o.size)if("c"===o.type)for(l=0;m>l;l++)h=v[l][1],n=o.value[h],o.array[g]=n.r,o.array[g+1]=n.g,o.array[g+2]=n.b,g+=3;else for(l=0;m>l;l++)h=v[l][1],n=o.value[h],o.array[g]=n.x,o.array[g+1]=n.y,o.array[g+2]=n.z,g+=3;else if(4===o.size)for(l=0;m>l;l++)h=v[l][1],n=o.value[h],o.array[g]=n.x,o.array[g+1]=n.y,o.array[g+2]=n.z,o.array[g+3]=n.w,g+=4}else{if(w)for(d=0;q>d;d++)f=p[d],g=3*d,t[g]=f.x,t[g+1]=f.y,t[g+2]=f.z;if(x)for(e=0;s>e;e++)i=r[e],g=3*e,u[g]=i.r,u[g+1]=i.g,u[g+2]=i.b;if(y)for(j=0,k=y.length;k>j;j++)if(o=y[j],o.needsUpdate&&(void 0===o.boundTo||"vertices"===o.boundTo))if(m=o.value.length,g=0,1===o.size)for(l=0;m>l;l++)o.array[l]=o.value[l];else if(2===o.size)for(l=0;m>l;l++)n=o.value[l],o.array[g]=n.x,o.array[g+1]=n.y,g+=2;else if(3===o.size)if("c"===o.type)for(l=0;m>l;l++)n=o.value[l],o.array[g]=n.r,o.array[g+1]=n.g,o.array[g+2]=n.b,g+=3;else for(l=0;m>l;l++)n=o.value[l],o.array[g]=n.x,o.array[g+1]=n.y,o.array[g+2]=n.z,g+=3;else if(4===o.size)for(l=0;m>l;l++)n=o.value[l],o.array[g]=n.x,o.array[g+1]=n.y,o.array[g+2]=n.z,o.array[g+3]=n.w,g+=4}if((w||c.sortParticles)&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglVertexBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,t,b)),(x||c.sortParticles)&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglColorBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,u,b)),y)for(j=0,k=y.length;k>j;j++)o=y[j],(o.needsUpdate||c.sortParticles)&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,o.buffer),Kb.bufferData(Kb.ARRAY_BUFFER,o.array,b))}function r(a,b){var c,d,e,f,g,h,i,j,k,l,m,n,o=a.vertices,p=a.colors,q=a.lineDistances,r=o.length,s=p.length,t=q.length,u=a.__vertexArray,v=a.__colorArray,w=a.__lineDistanceArray,x=a.verticesNeedUpdate,y=a.colorsNeedUpdate,z=a.lineDistancesNeedUpdate,A=a.__webglCustomAttributesList; -if(x){for(c=0;r>c;c++)f=o[c],g=3*c,u[g]=f.x,u[g+1]=f.y,u[g+2]=f.z;Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglVertexBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,u,b)}if(y){for(d=0;s>d;d++)h=p[d],g=3*d,v[g]=h.r,v[g+1]=h.g,v[g+2]=h.b;Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglColorBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,v,b)}if(z){for(e=0;t>e;e++)w[e]=q[e];Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglLineDistanceBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,w,b)}if(A)for(i=0,j=A.length;j>i;i++)if(n=A[i],n.needsUpdate&&(void 0===n.boundTo||"vertices"===n.boundTo)){if(g=0,l=n.value.length,1===n.size)for(k=0;l>k;k++)n.array[k]=n.value[k];else if(2===n.size)for(k=0;l>k;k++)m=n.value[k],n.array[g]=m.x,n.array[g+1]=m.y,g+=2;else if(3===n.size)if("c"===n.type)for(k=0;l>k;k++)m=n.value[k],n.array[g]=m.r,n.array[g+1]=m.g,n.array[g+2]=m.b,g+=3;else for(k=0;l>k;k++)m=n.value[k],n.array[g]=m.x,n.array[g+1]=m.y,n.array[g+2]=m.z,g+=3;else if(4===n.size)for(k=0;l>k;k++)m=n.value[k],n.array[g]=m.x,n.array[g+1]=m.y,n.array[g+2]=m.z,n.array[g+3]=m.w,g+=4;Kb.bindBuffer(Kb.ARRAY_BUFFER,n.buffer),Kb.bufferData(Kb.ARRAY_BUFFER,n.array,b)}}function s(a,b,c,d,f){if(a.__inittedArrays){var g,h,i,j,k,l,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z=m(f),$=n(f),_=o(f),ab=Z===e.SmoothShading,bb=0,cb=0,db=0,eb=0,fb=0,gb=0,hb=0,ib=0,jb=0,kb=0,lb=0,mb=0,nb=0,ob=a.__vertexArray,pb=a.__uvArray,qb=a.__uv2Array,rb=a.__normalArray,sb=a.__tangentArray,tb=a.__colorArray,ub=a.__skinIndexArray,vb=a.__skinWeightArray,wb=a.__morphTargetsArrays,xb=a.__morphNormalsArrays,yb=a.__webglCustomAttributesList,zb=a.__faceArray,Ab=a.__lineArray,Bb=b.geometry,Cb=Bb.verticesNeedUpdate,Db=Bb.elementsNeedUpdate,Eb=Bb.uvsNeedUpdate,Fb=Bb.normalsNeedUpdate,Gb=Bb.tangentsNeedUpdate,Hb=Bb.colorsNeedUpdate,Ib=Bb.morphTargetsNeedUpdate,Jb=Bb.vertices,Lb=a.faces3,Mb=Bb.faces,Nb=Bb.faceVertexUvs[0],Ob=Bb.faceVertexUvs[1],Pb=(Bb.colors,Bb.skinIndices),Qb=Bb.skinWeights,Rb=Bb.morphTargets,Sb=Bb.morphNormals;if(Cb){for(g=0,h=Lb.length;h>g;g++)j=Mb[Lb[g]],u=Jb[j.a],v=Jb[j.b],w=Jb[j.c],ob[cb]=u.x,ob[cb+1]=u.y,ob[cb+2]=u.z,ob[cb+3]=v.x,ob[cb+4]=v.y,ob[cb+5]=v.z,ob[cb+6]=w.x,ob[cb+7]=w.y,ob[cb+8]=w.z,cb+=9;Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglVertexBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,ob,c)}if(Ib)for(R=0,S=Rb.length;S>R;R++){for(lb=0,g=0,h=Lb.length;h>g;g++)V=Lb[g],j=Mb[V],u=Rb[R].vertices[j.a],v=Rb[R].vertices[j.b],w=Rb[R].vertices[j.c],T=wb[R],T[lb]=u.x,T[lb+1]=u.y,T[lb+2]=u.z,T[lb+3]=v.x,T[lb+4]=v.y,T[lb+5]=v.z,T[lb+6]=w.x,T[lb+7]=w.y,T[lb+8]=w.z,f.morphNormals&&(ab?(W=Sb[R].vertexNormals[V],A=W.a,B=W.b,C=W.c):(A=Sb[R].faceNormals[V],B=A,C=A),U=xb[R],U[lb]=A.x,U[lb+1]=A.y,U[lb+2]=A.z,U[lb+3]=B.x,U[lb+4]=B.y,U[lb+5]=B.z,U[lb+6]=C.x,U[lb+7]=C.y,U[lb+8]=C.z),lb+=9;Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglMorphTargetsBuffers[R]),Kb.bufferData(Kb.ARRAY_BUFFER,wb[R],c),f.morphNormals&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglMorphNormalsBuffers[R]),Kb.bufferData(Kb.ARRAY_BUFFER,xb[R],c))}if(Qb.length){for(g=0,h=Lb.length;h>g;g++)j=Mb[Lb[g]],G=Qb[j.a],H=Qb[j.b],I=Qb[j.c],vb[kb]=G.x,vb[kb+1]=G.y,vb[kb+2]=G.z,vb[kb+3]=G.w,vb[kb+4]=H.x,vb[kb+5]=H.y,vb[kb+6]=H.z,vb[kb+7]=H.w,vb[kb+8]=I.x,vb[kb+9]=I.y,vb[kb+10]=I.z,vb[kb+11]=I.w,J=Pb[j.a],K=Pb[j.b],L=Pb[j.c],ub[kb]=J.x,ub[kb+1]=J.y,ub[kb+2]=J.z,ub[kb+3]=J.w,ub[kb+4]=K.x,ub[kb+5]=K.y,ub[kb+6]=K.z,ub[kb+7]=K.w,ub[kb+8]=L.x,ub[kb+9]=L.y,ub[kb+10]=L.z,ub[kb+11]=L.w,kb+=12;kb>0&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglSkinIndicesBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,ub,c),Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglSkinWeightsBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,vb,c))}if(Hb&&$){for(g=0,h=Lb.length;h>g;g++)j=Mb[Lb[g]],p=j.vertexColors,q=j.color,3===p.length&&$===e.VertexColors?(D=p[0],E=p[1],F=p[2]):(D=q,E=q,F=q),tb[jb]=D.r,tb[jb+1]=D.g,tb[jb+2]=D.b,tb[jb+3]=E.r,tb[jb+4]=E.g,tb[jb+5]=E.b,tb[jb+6]=F.r,tb[jb+7]=F.g,tb[jb+8]=F.b,jb+=9;jb>0&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglColorBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,tb,c))}if(Gb&&Bb.hasTangents){for(g=0,h=Lb.length;h>g;g++)j=Mb[Lb[g]],r=j.vertexTangents,x=r[0],y=r[1],z=r[2],sb[hb]=x.x,sb[hb+1]=x.y,sb[hb+2]=x.z,sb[hb+3]=x.w,sb[hb+4]=y.x,sb[hb+5]=y.y,sb[hb+6]=y.z,sb[hb+7]=y.w,sb[hb+8]=z.x,sb[hb+9]=z.y,sb[hb+10]=z.z,sb[hb+11]=z.w,hb+=12;Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglTangentBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,sb,c)}if(Fb&&Z){for(g=0,h=Lb.length;h>g;g++)if(j=Mb[Lb[g]],k=j.vertexNormals,l=j.normal,3===k.length&&ab)for(M=0;3>M;M++)O=k[M],rb[gb]=O.x,rb[gb+1]=O.y,rb[gb+2]=O.z,gb+=3;else for(M=0;3>M;M++)rb[gb]=l.x,rb[gb+1]=l.y,rb[gb+2]=l.z,gb+=3;Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglNormalBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,rb,c)}if(Eb&&Nb&&_){for(g=0,h=Lb.length;h>g;g++)if(i=Lb[g],s=Nb[i],void 0!==s)for(M=0;3>M;M++)P=s[M],pb[db]=P.x,pb[db+1]=P.y,db+=2;db>0&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglUVBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,pb,c))}if(Eb&&Ob&&_){for(g=0,h=Lb.length;h>g;g++)if(i=Lb[g],t=Ob[i],void 0!==t)for(M=0;3>M;M++)Q=t[M],qb[eb]=Q.x,qb[eb+1]=Q.y,eb+=2;eb>0&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglUV2Buffer),Kb.bufferData(Kb.ARRAY_BUFFER,qb,c))}if(Db){for(g=0,h=Lb.length;h>g;g++)zb[fb]=bb,zb[fb+1]=bb+1,zb[fb+2]=bb+2,fb+=3,Ab[ib]=bb,Ab[ib+1]=bb+1,Ab[ib+2]=bb,Ab[ib+3]=bb+2,Ab[ib+4]=bb+1,Ab[ib+5]=bb+2,ib+=6,bb+=3;Kb.bindBuffer(Kb.ELEMENT_ARRAY_BUFFER,a.__webglFaceBuffer),Kb.bufferData(Kb.ELEMENT_ARRAY_BUFFER,zb,c),Kb.bindBuffer(Kb.ELEMENT_ARRAY_BUFFER,a.__webglLineBuffer),Kb.bufferData(Kb.ELEMENT_ARRAY_BUFFER,Ab,c)}if(yb)for(M=0,N=yb.length;N>M;M++)if(Y=yb[M],Y.__original.needsUpdate){if(mb=0,nb=0,1===Y.size){if(void 0===Y.boundTo||"vertices"===Y.boundTo)for(g=0,h=Lb.length;h>g;g++)j=Mb[Lb[g]],Y.array[mb]=Y.value[j.a],Y.array[mb+1]=Y.value[j.b],Y.array[mb+2]=Y.value[j.c],mb+=3;else if("faces"===Y.boundTo)for(g=0,h=Lb.length;h>g;g++)X=Y.value[Lb[g]],Y.array[mb]=X,Y.array[mb+1]=X,Y.array[mb+2]=X,mb+=3}else if(2===Y.size){if(void 0===Y.boundTo||"vertices"===Y.boundTo)for(g=0,h=Lb.length;h>g;g++)j=Mb[Lb[g]],u=Y.value[j.a],v=Y.value[j.b],w=Y.value[j.c],Y.array[mb]=u.x,Y.array[mb+1]=u.y,Y.array[mb+2]=v.x,Y.array[mb+3]=v.y,Y.array[mb+4]=w.x,Y.array[mb+5]=w.y,mb+=6;else if("faces"===Y.boundTo)for(g=0,h=Lb.length;h>g;g++)X=Y.value[Lb[g]],u=X,v=X,w=X,Y.array[mb]=u.x,Y.array[mb+1]=u.y,Y.array[mb+2]=v.x,Y.array[mb+3]=v.y,Y.array[mb+4]=w.x,Y.array[mb+5]=w.y,mb+=6}else if(3===Y.size){var Tb;if(Tb="c"===Y.type?["r","g","b"]:["x","y","z"],void 0===Y.boundTo||"vertices"===Y.boundTo)for(g=0,h=Lb.length;h>g;g++)j=Mb[Lb[g]],u=Y.value[j.a],v=Y.value[j.b],w=Y.value[j.c],Y.array[mb]=u[Tb[0]],Y.array[mb+1]=u[Tb[1]],Y.array[mb+2]=u[Tb[2]],Y.array[mb+3]=v[Tb[0]],Y.array[mb+4]=v[Tb[1]],Y.array[mb+5]=v[Tb[2]],Y.array[mb+6]=w[Tb[0]],Y.array[mb+7]=w[Tb[1]],Y.array[mb+8]=w[Tb[2]],mb+=9;else if("faces"===Y.boundTo)for(g=0,h=Lb.length;h>g;g++)X=Y.value[Lb[g]],u=X,v=X,w=X,Y.array[mb]=u[Tb[0]],Y.array[mb+1]=u[Tb[1]],Y.array[mb+2]=u[Tb[2]],Y.array[mb+3]=v[Tb[0]],Y.array[mb+4]=v[Tb[1]],Y.array[mb+5]=v[Tb[2]],Y.array[mb+6]=w[Tb[0]],Y.array[mb+7]=w[Tb[1]],Y.array[mb+8]=w[Tb[2]],mb+=9;else if("faceVertices"===Y.boundTo)for(g=0,h=Lb.length;h>g;g++)X=Y.value[Lb[g]],u=X[0],v=X[1],w=X[2],Y.array[mb]=u[Tb[0]],Y.array[mb+1]=u[Tb[1]],Y.array[mb+2]=u[Tb[2]],Y.array[mb+3]=v[Tb[0]],Y.array[mb+4]=v[Tb[1]],Y.array[mb+5]=v[Tb[2]],Y.array[mb+6]=w[Tb[0]],Y.array[mb+7]=w[Tb[1]],Y.array[mb+8]=w[Tb[2]],mb+=9}else if(4===Y.size)if(void 0===Y.boundTo||"vertices"===Y.boundTo)for(g=0,h=Lb.length;h>g;g++)j=Mb[Lb[g]],u=Y.value[j.a],v=Y.value[j.b],w=Y.value[j.c],Y.array[mb]=u.x,Y.array[mb+1]=u.y,Y.array[mb+2]=u.z,Y.array[mb+3]=u.w,Y.array[mb+4]=v.x,Y.array[mb+5]=v.y,Y.array[mb+6]=v.z,Y.array[mb+7]=v.w,Y.array[mb+8]=w.x,Y.array[mb+9]=w.y,Y.array[mb+10]=w.z,Y.array[mb+11]=w.w,mb+=12;else if("faces"===Y.boundTo)for(g=0,h=Lb.length;h>g;g++)X=Y.value[Lb[g]],u=X,v=X,w=X,Y.array[mb]=u.x,Y.array[mb+1]=u.y,Y.array[mb+2]=u.z,Y.array[mb+3]=u.w,Y.array[mb+4]=v.x,Y.array[mb+5]=v.y,Y.array[mb+6]=v.z,Y.array[mb+7]=v.w,Y.array[mb+8]=w.x,Y.array[mb+9]=w.y,Y.array[mb+10]=w.z,Y.array[mb+11]=w.w,mb+=12;else if("faceVertices"===Y.boundTo)for(g=0,h=Lb.length;h>g;g++)X=Y.value[Lb[g]],u=X[0],v=X[1],w=X[2],Y.array[mb]=u.x,Y.array[mb+1]=u.y,Y.array[mb+2]=u.z,Y.array[mb+3]=u.w,Y.array[mb+4]=v.x,Y.array[mb+5]=v.y,Y.array[mb+6]=v.z,Y.array[mb+7]=v.w,Y.array[mb+8]=w.x,Y.array[mb+9]=w.y,Y.array[mb+10]=w.z,Y.array[mb+11]=w.w,mb+=12;Kb.bindBuffer(Kb.ARRAY_BUFFER,Y.buffer),Kb.bufferData(Kb.ARRAY_BUFFER,Y.array,c)}d&&(delete a.__inittedArrays,delete a.__colorArray,delete a.__normalArray,delete a.__tangentArray,delete a.__uvArray,delete a.__uv2Array,delete a.__faceArray,delete a.__vertexArray,delete a.__lineArray,delete a.__skinIndexArray,delete a.__skinWeightArray)}}function t(a,b,c,d){var e,f,g,h;for(f in b)g=b[f],e=c[f],g>=0&&(e?(h=e.itemSize,Kb.bindBuffer(Kb.ARRAY_BUFFER,e.buffer),v(g),Kb.vertexAttribPointer(g,h,Kb.FLOAT,!1,0,d*h*4)):a.defaultAttributeValues&&(2===a.defaultAttributeValues[f].length?Kb.vertexAttrib2fv(g,a.defaultAttributeValues[f]):3===a.defaultAttributeValues[f].length&&Kb.vertexAttrib3fv(g,a.defaultAttributeValues[f])))}function u(a,b){var c,d,e=a.attributes;for(c in e)d=e[c],d.needsUpdate&&("index"===c?(Kb.bindBuffer(Kb.ELEMENT_ARRAY_BUFFER,d.buffer),Kb.bufferData(Kb.ELEMENT_ARRAY_BUFFER,d.array,b)):(Kb.bindBuffer(Kb.ARRAY_BUFFER,d.buffer),Kb.bufferData(Kb.ARRAY_BUFFER,d.array,b)),d.needsUpdate=!1)}function v(a){0===pc[a]&&(Kb.enableVertexAttribArray(a),pc[a]=1)}function w(){for(var a in pc)1===pc[a]&&(Kb.disableVertexAttribArray(a),pc[a]=0)}function x(a,b,c){var d=a.program.attributes;if(-1!==c.morphTargetBase&&d.position>=0?(Kb.bindBuffer(Kb.ARRAY_BUFFER,b.__webglMorphTargetsBuffers[c.morphTargetBase]),v(d.position),Kb.vertexAttribPointer(d.position,3,Kb.FLOAT,!1,0,0)):d.position>=0&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,b.__webglVertexBuffer),v(d.position),Kb.vertexAttribPointer(d.position,3,Kb.FLOAT,!1,0,0)),c.morphTargetForcedOrder.length)for(var e=0,f=c.morphTargetForcedOrder,g=c.morphTargetInfluences;e=0&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,b.__webglMorphTargetsBuffers[f[e]]),v(d["morphTarget"+e]),Kb.vertexAttribPointer(d["morphTarget"+e],3,Kb.FLOAT,!1,0,0)),d["morphNormal"+e]>=0&&a.morphNormals&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,b.__webglMorphNormalsBuffers[f[e]]),v(d["morphNormal"+e]),Kb.vertexAttribPointer(d["morphNormal"+e],3,Kb.FLOAT,!1,0,0)),c.__webglMorphTargetInfluences[e]=g[f[e]],e++;else{var h,i,j=[],g=c.morphTargetInfluences,k=g.length;for(i=0;k>i;i++)h=g[i],h>0&&j.push([h,i]);j.length>a.numSupportedMorphTargets?(j.sort(z),j.length=a.numSupportedMorphTargets):j.length>a.numSupportedMorphNormals?j.sort(z):0===j.length&&j.push([0,0]);for(var l,e=0;e=0&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,b.__webglMorphTargetsBuffers[l]),v(d["morphTarget"+e]),Kb.vertexAttribPointer(d["morphTarget"+e],3,Kb.FLOAT,!1,0,0)),d["morphNormal"+e]>=0&&a.morphNormals&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,b.__webglMorphNormalsBuffers[l]),v(d["morphNormal"+e]),Kb.vertexAttribPointer(d["morphNormal"+e],3,Kb.FLOAT,!1,0,0)),c.__webglMorphTargetInfluences[e]=g[l]):c.__webglMorphTargetInfluences[e]=0,e++}null!==a.program.uniforms.morphTargetInfluences&&Kb.uniform1fv(a.program.uniforms.morphTargetInfluences,c.__webglMorphTargetInfluences)}function y(a,b){return a.z!==b.z?b.z-a.z:a.id-b.id}function z(a,b){return b[0]-a[0]}function A(a,b,c){if(a.length)for(var d=0,e=a.length;e>d;d++)Tb=null,Xb=null,_b=-1,dc=-1,ec=-1,Zb=-1,$b=-1,Wb=-1,Vb=-1,vc=!0,a[d].render(b,c,nc,oc),Tb=null,Xb=null,_b=-1,dc=-1,ec=-1,Zb=-1,$b=-1,Wb=-1,Vb=-1,vc=!0}function B(a,b,c,d,f,g,h,i){var j,k,l,m,n,o,p;b?(n=a.length-1,o=-1,p=-1):(n=0,o=a.length,p=1);for(var q=n;q!==o;q+=p)if(j=a[q],j.render){if(k=j.object,l=j.buffer,i)m=i;else{if(m=j[c],!m)continue;h&&Qb.setBlending(m.blending,m.blendEquation,m.blendSrc,m.blendDst),Qb.setDepthTest(m.depthTest),Qb.setDepthWrite(m.depthWrite),fb(m.polygonOffset,m.polygonOffsetFactor,m.polygonOffsetUnits)}Qb.setMaterialFaces(m),l instanceof e.BufferGeometry?Qb.renderBufferDirect(d,f,g,m,l,k):Qb.renderBuffer(d,f,g,m,l,k)}}function C(a,b,c,d,e,f,g){for(var h,i,j,k=0,l=a.length;l>k;k++)if(h=a[k],i=h.object,i.visible){if(g)j=g;else{if(j=h[b],!j)continue;f&&Qb.setBlending(j.blending,j.blendEquation,j.blendSrc,j.blendDst),Qb.setDepthTest(j.depthTest),Qb.setDepthWrite(j.depthWrite),fb(j.polygonOffset,j.polygonOffsetFactor,j.polygonOffsetUnits)}Qb.renderImmediateObject(c,d,e,j,i)}}function D(a){var b=a.object,c=b.material;c.transparent?(a.transparent=c,a.opaque=null):(a.opaque=c,a.transparent=null)}function E(a){var b=a.object,c=a.buffer,d=b.geometry,f=b.material;if(f instanceof e.MeshFaceMaterial){var g=d instanceof e.BufferGeometry?0:c.materialIndex;f=f.materials[g],f.transparent?(a.transparent=f,a.opaque=null):(a.opaque=f,a.transparent=null)}else f&&(f.transparent?(a.transparent=f,a.opaque=null):(a.opaque=f,a.transparent=null))}function F(a,d){var g,k,l,m;if(void 0===a.__webglInit)if(a.__webglInit=!0,a._modelViewMatrix=new e.Matrix4,a._normalMatrix=new e.Matrix3,void 0!==a.geometry&&void 0===a.geometry.__webglInit&&(a.geometry.__webglInit=!0,a.geometry.addEventListener("dispose",Jc)),k=a.geometry,void 0===k);else if(k instanceof e.BufferGeometry)p(k);else if(a instanceof e.Mesh){l=a.material,void 0===k.geometryGroups&&k.makeGroups(l instanceof e.MeshFaceMaterial);for(g in k.geometryGroups)m=k.geometryGroups[g],m.__webglVertexBuffer||(f(m),j(m,a),k.verticesNeedUpdate=!0,k.morphTargetsNeedUpdate=!0,k.elementsNeedUpdate=!0,k.uvsNeedUpdate=!0,k.normalsNeedUpdate=!0,k.tangentsNeedUpdate=!0,k.colorsNeedUpdate=!0)}else a instanceof e.Line?k.__webglVertexBuffer||(c(k),i(k,a),k.verticesNeedUpdate=!0,k.colorsNeedUpdate=!0,k.lineDistancesNeedUpdate=!0):a instanceof e.ParticleSystem&&(k.__webglVertexBuffer||(b(k),h(k,a),k.verticesNeedUpdate=!0,k.colorsNeedUpdate=!0));if(void 0===a.__webglActive){if(a instanceof e.Mesh){if(k=a.geometry,k instanceof e.BufferGeometry)G(d.__webglObjects,k,a);else if(k instanceof e.Geometry)for(g in k.geometryGroups)m=k.geometryGroups[g],G(d.__webglObjects,m,a)}else a instanceof e.Line||a instanceof e.ParticleSystem?(k=a.geometry,G(d.__webglObjects,k,a)):a instanceof e.ImmediateRenderObject||a.immediateRenderCallback?H(d.__webglObjectsImmediate,a):a instanceof e.Sprite?d.__webglSprites.push(a):a instanceof e.LensFlare&&d.__webglFlares.push(a);a.__webglActive=!0}}function G(a,b,c){a.push({id:null,buffer:b,object:c,opaque:null,transparent:null,z:0})}function H(a,b){a.push({id:null,object:b,opaque:null,transparent:null,z:0})}function I(a){var b,c,d,f=a.geometry;if(f instanceof e.BufferGeometry)u(f,Kb.DYNAMIC_DRAW);else if(a instanceof e.Mesh){for(var g=0,h=f.geometryGroupsList.length;h>g;g++)b=f.geometryGroupsList[g],d=k(a,b),f.buffersNeedUpdate&&j(b,a),c=d.attributes&&J(d),(f.verticesNeedUpdate||f.morphTargetsNeedUpdate||f.elementsNeedUpdate||f.uvsNeedUpdate||f.normalsNeedUpdate||f.colorsNeedUpdate||f.tangentsNeedUpdate||c)&&s(b,a,Kb.DYNAMIC_DRAW,!f.dynamic,d);f.verticesNeedUpdate=!1,f.morphTargetsNeedUpdate=!1,f.elementsNeedUpdate=!1,f.uvsNeedUpdate=!1,f.normalsNeedUpdate=!1,f.colorsNeedUpdate=!1,f.tangentsNeedUpdate=!1,f.buffersNeedUpdate=!1,d.attributes&&K(d)}else a instanceof e.Line?(d=k(a,f),c=d.attributes&&J(d),(f.verticesNeedUpdate||f.colorsNeedUpdate||f.lineDistancesNeedUpdate||c)&&r(f,Kb.DYNAMIC_DRAW),f.verticesNeedUpdate=!1,f.colorsNeedUpdate=!1,f.lineDistancesNeedUpdate=!1,d.attributes&&K(d)):a instanceof e.ParticleSystem&&(d=k(a,f),c=d.attributes&&J(d),(f.verticesNeedUpdate||f.colorsNeedUpdate||a.sortParticles||c)&&q(f,Kb.DYNAMIC_DRAW,a),f.verticesNeedUpdate=!1,f.colorsNeedUpdate=!1,d.attributes&&K(d))}function J(a){for(var b in a.attributes)if(a.attributes[b].needsUpdate)return!0;return!1}function K(a){for(var b in a.attributes)a.attributes[b].needsUpdate=!1}function L(a,b){a instanceof e.Mesh||a instanceof e.ParticleSystem||a instanceof e.Line?M(b.__webglObjects,a):a instanceof e.Sprite?N(b.__webglSprites,a):a instanceof e.LensFlare?N(b.__webglFlares,a):(a instanceof e.ImmediateRenderObject||a.immediateRenderCallback)&&M(b.__webglObjectsImmediate,a),delete a.__webglActive}function M(a,b){for(var c=a.length-1;c>=0;c--)a[c].object===b&&a.splice(c,1)}function N(a,b){for(var c=a.length-1;c>=0;c--)a[c]===b&&a.splice(c,1)}function O(a,b){a.uniforms=e.UniformsUtils.clone(b.uniforms),a.vertexShader=b.vertexShader,a.fragmentShader=b.fragmentShader}function P(a,b,c,d,f){Yb=0,d.needsUpdate&&(d.program&&Rc(d),Qb.initMaterial(d,b,c,f),d.needsUpdate=!1),d.morphTargets&&(f.__webglMorphTargetInfluences||(f.__webglMorphTargetInfluences=new Float32Array(Qb.maxMorphTargets)));var g=!1,h=d.program,i=h.uniforms,j=d.uniforms;if(h!==Tb&&(Kb.useProgram(h),Tb=h,g=!0),d.id!==Vb&&(Vb=d.id,g=!0),(g||a!==Xb)&&(Kb.uniformMatrix4fv(i.projectionMatrix,!1,a.projectionMatrix.elements),a!==Xb&&(Xb=a)),d.skinning)if(Cc&&f.useVertexTexture){if(null!==i.boneTexture){var k=$();Kb.uniform1i(i.boneTexture,k),Qb.setTexture(f.boneTexture,k)}null!==i.boneTextureWidth&&Kb.uniform1i(i.boneTextureWidth,f.boneTextureWidth),null!==i.boneTextureHeight&&Kb.uniform1i(i.boneTextureHeight,f.boneTextureHeight)}else null!==i.boneGlobalMatrices&&Kb.uniformMatrix4fv(i.boneGlobalMatrices,!1,f.boneMatrices);return g&&(c&&d.fog&&U(j,c),(d instanceof e.MeshPhongMaterial||d instanceof e.MeshLambertMaterial||d.lights)&&(vc&&(db(h,b),vc=!1),X(j,wc)),(d instanceof e.MeshBasicMaterial||d instanceof e.MeshLambertMaterial||d instanceof e.MeshPhongMaterial)&&Q(j,d),d instanceof e.LineBasicMaterial?R(j,d):d instanceof e.LineDashedMaterial?(R(j,d),S(j,d)):d instanceof e.ParticleSystemMaterial?T(j,d):d instanceof e.MeshPhongMaterial?V(j,d):d instanceof e.MeshLambertMaterial?W(j,d):d instanceof e.MeshDepthMaterial?(j.mNear.value=a.near,j.mFar.value=a.far,j.opacity.value=d.opacity):d instanceof e.MeshNormalMaterial&&(j.opacity.value=d.opacity),f.receiveShadow&&!d._shadowPass&&Y(j,b),_(h,d.uniformsList),(d instanceof e.ShaderMaterial||d instanceof e.MeshPhongMaterial||d.envMap)&&null!==i.cameraPosition&&(tc.setFromMatrixPosition(a.matrixWorld),Kb.uniform3f(i.cameraPosition,tc.x,tc.y,tc.z)),(d instanceof e.MeshPhongMaterial||d instanceof e.MeshLambertMaterial||d instanceof e.ShaderMaterial||d.skinning)&&null!==i.viewMatrix&&Kb.uniformMatrix4fv(i.viewMatrix,!1,a.matrixWorldInverse.elements)),Z(i,f),null!==i.modelMatrix&&Kb.uniformMatrix4fv(i.modelMatrix,!1,f.matrixWorld.elements),h}function Q(a,b){a.opacity.value=b.opacity,Qb.gammaInput?a.diffuse.value.copyGammaToLinear(b.color):a.diffuse.value=b.color,a.map.value=b.map,a.lightMap.value=b.lightMap,a.specularMap.value=b.specularMap,b.bumpMap&&(a.bumpMap.value=b.bumpMap,a.bumpScale.value=b.bumpScale),b.normalMap&&(a.normalMap.value=b.normalMap,a.normalScale.value.copy(b.normalScale));var c;if(b.map?c=b.map:b.specularMap?c=b.specularMap:b.normalMap?c=b.normalMap:b.bumpMap&&(c=b.bumpMap),void 0!==c){var d=c.offset,f=c.repeat;a.offsetRepeat.value.set(d.x,d.y,f.x,f.y)}a.envMap.value=b.envMap,a.flipEnvMap.value=b.envMap instanceof e.WebGLRenderTargetCube?1:-1,a.reflectivity.value=Qb.gammaInput?b.reflectivity:b.reflectivity,a.refractionRatio.value=b.refractionRatio,a.combine.value=b.combine,a.useRefract.value=b.envMap&&b.envMap.mapping instanceof e.CubeRefractionMapping}function R(a,b){a.diffuse.value=b.color,a.opacity.value=b.opacity}function S(a,b){a.dashSize.value=b.dashSize,a.totalSize.value=b.dashSize+b.gapSize,a.scale.value=b.scale}function T(a,b){a.psColor.value=b.color,a.opacity.value=b.opacity,a.size.value=b.size,a.scale.value=Ab.height/2,a.map.value=b.map}function U(a,b){a.fogColor.value=b.color,b instanceof e.Fog?(a.fogNear.value=b.near,a.fogFar.value=b.far):b instanceof e.FogExp2&&(a.fogDensity.value=b.density)}function V(a,b){a.shininess.value=b.shininess,Qb.gammaInput?(a.ambient.value.copyGammaToLinear(b.ambient),a.emissive.value.copyGammaToLinear(b.emissive),a.specular.value.copyGammaToLinear(b.specular)):(a.ambient.value=b.ambient,a.emissive.value=b.emissive,a.specular.value=b.specular),b.wrapAround&&a.wrapRGB.value.copy(b.wrapRGB)}function W(a,b){Qb.gammaInput?(a.ambient.value.copyGammaToLinear(b.ambient),a.emissive.value.copyGammaToLinear(b.emissive)):(a.ambient.value=b.ambient,a.emissive.value=b.emissive),b.wrapAround&&a.wrapRGB.value.copy(b.wrapRGB)}function X(a,b){a.ambientLightColor.value=b.ambient,a.directionalLightColor.value=b.directional.colors,a.directionalLightDirection.value=b.directional.positions,a.pointLightColor.value=b.point.colors,a.pointLightPosition.value=b.point.positions,a.pointLightDistance.value=b.point.distances,a.spotLightColor.value=b.spot.colors,a.spotLightPosition.value=b.spot.positions,a.spotLightDistance.value=b.spot.distances,a.spotLightDirection.value=b.spot.directions,a.spotLightAngleCos.value=b.spot.anglesCos,a.spotLightExponent.value=b.spot.exponents,a.hemisphereLightSkyColor.value=b.hemi.skyColors,a.hemisphereLightGroundColor.value=b.hemi.groundColors,a.hemisphereLightDirection.value=b.hemi.positions}function Y(a,b){if(a.shadowMatrix)for(var c=0,d=0,f=b.length;f>d;d++){var g=b[d];g.castShadow&&(g instanceof e.SpotLight||g instanceof e.DirectionalLight&&!g.shadowCascade)&&(a.shadowMap.value[c]=g.shadowMap,a.shadowMapSize.value[c]=g.shadowMapSize,a.shadowMatrix.value[c]=g.shadowMatrix,a.shadowDarkness.value[c]=g.shadowDarkness,a.shadowBias.value[c]=g.shadowBias,c++)}}function Z(a,b){Kb.uniformMatrix4fv(a.modelViewMatrix,!1,b._modelViewMatrix.elements),a.normalMatrix&&Kb.uniformMatrix3fv(a.normalMatrix,!1,b._normalMatrix.elements)}function $(){var a=Yb;return a>=xc&&console.warn("WebGLRenderer: trying to use "+a+" texture units while this GPU supports only "+xc),Yb+=1,a}function _(a,b){var c,d,f,g,h,i,j,k,l,m,n;for(l=0,m=b.length;m>l;l++)if(g=a.uniforms[b[l][1]])if(c=b[l][0],f=c.type,d=c.value,"i"===f)Kb.uniform1i(g,d);else if("f"===f)Kb.uniform1f(g,d);else if("v2"===f)Kb.uniform2f(g,d.x,d.y);else if("v3"===f)Kb.uniform3f(g,d.x,d.y,d.z);else if("v4"===f)Kb.uniform4f(g,d.x,d.y,d.z,d.w);else if("c"===f)Kb.uniform3f(g,d.r,d.g,d.b);else if("iv1"===f)Kb.uniform1iv(g,d);else if("iv"===f)Kb.uniform3iv(g,d);else if("fv1"===f)Kb.uniform1fv(g,d);else if("fv"===f)Kb.uniform3fv(g,d);else if("v2v"===f){for(void 0===c._array&&(c._array=new Float32Array(2*d.length)),j=0,k=d.length;k>j;j++)n=2*j,c._array[n]=d[j].x,c._array[n+1]=d[j].y;Kb.uniform2fv(g,c._array)}else if("v3v"===f){for(void 0===c._array&&(c._array=new Float32Array(3*d.length)),j=0,k=d.length;k>j;j++)n=3*j,c._array[n]=d[j].x,c._array[n+1]=d[j].y,c._array[n+2]=d[j].z;Kb.uniform3fv(g,c._array)}else if("v4v"===f){for(void 0===c._array&&(c._array=new Float32Array(4*d.length)),j=0,k=d.length;k>j;j++)n=4*j,c._array[n]=d[j].x,c._array[n+1]=d[j].y,c._array[n+2]=d[j].z,c._array[n+3]=d[j].w;Kb.uniform4fv(g,c._array)}else if("m4"===f)void 0===c._array&&(c._array=new Float32Array(16)),d.flattenToArray(c._array),Kb.uniformMatrix4fv(g,!1,c._array);else if("m4v"===f){for(void 0===c._array&&(c._array=new Float32Array(16*d.length)),j=0,k=d.length;k>j;j++)d[j].flattenToArrayOffset(c._array,16*j);Kb.uniformMatrix4fv(g,!1,c._array)}else if("t"===f){if(h=d,i=$(),Kb.uniform1i(g,i),!h)continue;h.image instanceof Array&&6===h.image.length?ob(h,i):h instanceof e.WebGLRenderTargetCube?pb(h,i):Qb.setTexture(h,i)}else if("tv"===f){for(void 0===c._array&&(c._array=[]),j=0,k=c.value.length;k>j;j++)c._array[j]=$();for(Kb.uniform1iv(g,c._array),j=0,k=c.value.length;k>j;j++)h=c.value[j],i=c._array[j],h&&Qb.setTexture(h,i)}else console.warn("THREE.WebGLRenderer: Unknown uniform type: "+f)}function ab(a,b){a._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,a.matrixWorld),a._normalMatrix.getNormalMatrix(a._modelViewMatrix)}function bb(a,b,c,d){a[b]=c.r*c.r*d,a[b+1]=c.g*c.g*d,a[b+2]=c.b*c.b*d}function cb(a,b,c,d){a[b]=c.r*d,a[b+1]=c.g*d,a[b+2]=c.b*d}function db(a,b){var c,d,f,g,h,i,j,k,l,m=0,n=0,o=0,p=wc,q=p.directional.colors,r=p.directional.positions,s=p.point.colors,t=p.point.positions,u=p.point.distances,v=p.spot.colors,w=p.spot.positions,x=p.spot.distances,y=p.spot.directions,z=p.spot.anglesCos,A=p.spot.exponents,B=p.hemi.skyColors,C=p.hemi.groundColors,D=p.hemi.positions,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0;for(c=0,d=b.length;d>c;c++)if(f=b[c],!f.onlyShadow)if(g=f.color,j=f.intensity,l=f.distance,f instanceof e.AmbientLight){if(!f.visible)continue;Qb.gammaInput?(m+=g.r*g.r,n+=g.g*g.g,o+=g.b*g.b):(m+=g.r,n+=g.g,o+=g.b)}else if(f instanceof e.DirectionalLight){if(I+=1,!f.visible)continue;if(uc.setFromMatrixPosition(f.matrixWorld),tc.setFromMatrixPosition(f.target.matrixWorld),uc.sub(tc),uc.normalize(),0===uc.x&&0===uc.y&&0===uc.z)continue;M=3*E,r[M]=uc.x,r[M+1]=uc.y,r[M+2]=uc.z,Qb.gammaInput?bb(q,M,g,j*j):cb(q,M,g,j),E+=1}else if(f instanceof e.PointLight){if(J+=1,!f.visible)continue;N=3*F,Qb.gammaInput?bb(s,N,g,j*j):cb(s,N,g,j),tc.setFromMatrixPosition(f.matrixWorld),t[N]=tc.x,t[N+1]=tc.y,t[N+2]=tc.z,u[F]=l,F+=1}else if(f instanceof e.SpotLight){if(K+=1,!f.visible)continue;O=3*G,Qb.gammaInput?bb(v,O,g,j*j):cb(v,O,g,j),tc.setFromMatrixPosition(f.matrixWorld),w[O]=tc.x,w[O+1]=tc.y,w[O+2]=tc.z,x[G]=l,uc.copy(tc),tc.setFromMatrixPosition(f.target.matrixWorld),uc.sub(tc),uc.normalize(),y[O]=uc.x,y[O+1]=uc.y,y[O+2]=uc.z,z[G]=Math.cos(f.angle),A[G]=f.exponent,G+=1}else if(f instanceof e.HemisphereLight){if(L+=1,!f.visible)continue;if(uc.setFromMatrixPosition(f.matrixWorld),uc.normalize(),0===uc.x&&0===uc.y&&0===uc.z)continue;P=3*H,D[P]=uc.x,D[P+1]=uc.y,D[P+2]=uc.z,h=f.color,i=f.groundColor,Qb.gammaInput?(k=j*j,bb(B,P,h,k),bb(C,P,i,k)):(cb(B,P,h,j),cb(C,P,i,j)),H+=1}for(c=3*E,d=Math.max(q.length,3*I);d>c;c++)q[c]=0;for(c=3*F,d=Math.max(s.length,3*J);d>c;c++)s[c]=0;for(c=3*G,d=Math.max(v.length,3*K);d>c;c++)v[c]=0;for(c=3*H,d=Math.max(B.length,3*L);d>c;c++)B[c]=0;for(c=3*H,d=Math.max(C.length,3*L);d>c;c++)C[c]=0;p.directional.length=E,p.point.length=F,p.spot.length=G,p.hemi.length=H,p.ambient[0]=m,p.ambient[1]=n,p.ambient[2]=o}function eb(a){a!==ic&&(Kb.lineWidth(a),ic=a)}function fb(a,b,c){fc!==a&&(a?Kb.enable(Kb.POLYGON_OFFSET_FILL):Kb.disable(Kb.POLYGON_OFFSET_FILL),fc=a),!a||gc===b&&hc===c||(Kb.polygonOffset(b,c),gc=b,hc=c)}function gb(a){var b,c,d=[];for(var e in a)b=a[e],b!==!1&&(c="#define "+e+" "+b,d.push(c));return d.join("\n")}function hb(a,b,c,d,f,g,h,i){var j,k,l,m,n,o=[];a?o.push(a):(o.push(b),o.push(c));for(l in g)o.push(l),o.push(g[l]);for(j in h)o.push(j),o.push(h[j]);for(n=o.join(),j=0,k=Rb.length;k>j;j++){var p=Rb[j];if(p.code===n)return p.usedTimes++,p.program}var q="SHADOWMAP_TYPE_BASIC";h.shadowMapType===e.PCFShadowMap?q="SHADOWMAP_TYPE_PCF":h.shadowMapType===e.PCFSoftShadowMap&&(q="SHADOWMAP_TYPE_PCF_SOFT");var r=gb(g);m=Kb.createProgram();var s=["precision "+Cb+" float;","precision "+Cb+" int;",r,Bc?"#define VERTEX_TEXTURES":"",Qb.gammaInput?"#define GAMMA_INPUT":"",Qb.gammaOutput?"#define GAMMA_OUTPUT":"","#define MAX_DIR_LIGHTS "+h.maxDirLights,"#define MAX_POINT_LIGHTS "+h.maxPointLights,"#define MAX_SPOT_LIGHTS "+h.maxSpotLights,"#define MAX_HEMI_LIGHTS "+h.maxHemiLights,"#define MAX_SHADOWS "+h.maxShadows,"#define MAX_BONES "+h.maxBones,h.map?"#define USE_MAP":"",h.envMap?"#define USE_ENVMAP":"",h.lightMap?"#define USE_LIGHTMAP":"",h.bumpMap?"#define USE_BUMPMAP":"",h.normalMap?"#define USE_NORMALMAP":"",h.specularMap?"#define USE_SPECULARMAP":"",h.vertexColors?"#define USE_COLOR":"",h.skinning?"#define USE_SKINNING":"",h.useVertexTexture?"#define BONE_TEXTURE":"",h.morphTargets?"#define USE_MORPHTARGETS":"",h.morphNormals?"#define USE_MORPHNORMALS":"",h.wrapAround?"#define WRAP_AROUND":"",h.doubleSided?"#define DOUBLE_SIDED":"",h.flipSided?"#define FLIP_SIDED":"",h.shadowMapEnabled?"#define USE_SHADOWMAP":"",h.shadowMapEnabled?"#define "+q:"",h.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",h.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",h.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","attribute vec2 uv2;","#ifdef USE_COLOR","attribute vec3 color;","#endif","#ifdef USE_MORPHTARGETS","attribute vec3 morphTarget0;","attribute vec3 morphTarget1;","attribute vec3 morphTarget2;","attribute vec3 morphTarget3;","#ifdef USE_MORPHNORMALS","attribute vec3 morphNormal0;","attribute vec3 morphNormal1;","attribute vec3 morphNormal2;","attribute vec3 morphNormal3;","#else","attribute vec3 morphTarget4;","attribute vec3 morphTarget5;","attribute vec3 morphTarget6;","attribute vec3 morphTarget7;","#endif","#endif","#ifdef USE_SKINNING","attribute vec4 skinIndex;","attribute vec4 skinWeight;","#endif",""].join("\n"),t=["precision "+Cb+" float;","precision "+Cb+" int;",h.bumpMap||h.normalMap?"#extension GL_OES_standard_derivatives : enable":"",r,"#define MAX_DIR_LIGHTS "+h.maxDirLights,"#define MAX_POINT_LIGHTS "+h.maxPointLights,"#define MAX_SPOT_LIGHTS "+h.maxSpotLights,"#define MAX_HEMI_LIGHTS "+h.maxHemiLights,"#define MAX_SHADOWS "+h.maxShadows,h.alphaTest?"#define ALPHATEST "+h.alphaTest:"",Qb.gammaInput?"#define GAMMA_INPUT":"",Qb.gammaOutput?"#define GAMMA_OUTPUT":"",h.useFog&&h.fog?"#define USE_FOG":"",h.useFog&&h.fogExp?"#define FOG_EXP2":"",h.map?"#define USE_MAP":"",h.envMap?"#define USE_ENVMAP":"",h.lightMap?"#define USE_LIGHTMAP":"",h.bumpMap?"#define USE_BUMPMAP":"",h.normalMap?"#define USE_NORMALMAP":"",h.specularMap?"#define USE_SPECULARMAP":"",h.vertexColors?"#define USE_COLOR":"",h.metal?"#define METAL":"",h.wrapAround?"#define WRAP_AROUND":"",h.doubleSided?"#define DOUBLE_SIDED":"",h.flipSided?"#define FLIP_SIDED":"",h.shadowMapEnabled?"#define USE_SHADOWMAP":"",h.shadowMapEnabled?"#define "+q:"",h.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",h.shadowMapCascade?"#define SHADOWMAP_CASCADE":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;",""].join("\n"),u=lb("vertex",s+c),v=lb("fragment",t+b);Kb.attachShader(m,u),Kb.attachShader(m,v),void 0!==i&&Kb.bindAttribLocation(m,0,i),Kb.linkProgram(m),Kb.getProgramParameter(m,Kb.LINK_STATUS)===!1&&(console.error("Could not initialise shader"),console.error("gl.VALIDATE_STATUS",Kb.getProgramParameter(m,Kb.VALIDATE_STATUS)),console.error("gl.getError()",Kb.getError())),""!==Kb.getProgramInfoLog(m)&&console.error("gl.getProgramInfoLog()",Kb.getProgramInfoLog(m)),Kb.deleteShader(v),Kb.deleteShader(u),m.uniforms={},m.attributes={};var w,x,y,z;w=["viewMatrix","modelViewMatrix","projectionMatrix","normalMatrix","modelMatrix","cameraPosition","morphTargetInfluences"],h.useVertexTexture?(w.push("boneTexture"),w.push("boneTextureWidth"),w.push("boneTextureHeight")):w.push("boneGlobalMatrices");for(x in d)w.push(x);for(ib(m,w),w=["position","normal","uv","uv2","tangent","color","skinIndex","skinWeight","lineDistance"],z=0;zc;c++)e=b[c],a.uniforms[e]=Kb.getUniformLocation(a,e)}function jb(a,b){var c,d,e;for(c=0,d=b.length;d>c;c++)e=b[c],a.attributes[e]=Kb.getAttribLocation(a,e)}function kb(a){for(var b=a.split("\n"),c=0,d=b.length;d>c;c++)b[c]=c+1+": "+b[c];return b.join("\n")}function lb(a,b){var c;return"fragment"===a?c=Kb.createShader(Kb.FRAGMENT_SHADER):"vertex"===a&&(c=Kb.createShader(Kb.VERTEX_SHADER)),Kb.shaderSource(c,b),Kb.compileShader(c),Kb.getShaderParameter(c,Kb.COMPILE_STATUS)?c:(console.error(Kb.getShaderInfoLog(c)),console.error(kb(b)),null)}function mb(a,b,c){c?(Kb.texParameteri(a,Kb.TEXTURE_WRAP_S,ub(b.wrapS)),Kb.texParameteri(a,Kb.TEXTURE_WRAP_T,ub(b.wrapT)),Kb.texParameteri(a,Kb.TEXTURE_MAG_FILTER,ub(b.magFilter)),Kb.texParameteri(a,Kb.TEXTURE_MIN_FILTER,ub(b.minFilter))):(Kb.texParameteri(a,Kb.TEXTURE_WRAP_S,Kb.CLAMP_TO_EDGE),Kb.texParameteri(a,Kb.TEXTURE_WRAP_T,Kb.CLAMP_TO_EDGE),Kb.texParameteri(a,Kb.TEXTURE_MAG_FILTER,tb(b.magFilter)),Kb.texParameteri(a,Kb.TEXTURE_MIN_FILTER,tb(b.minFilter))),Ob&&b.type!==e.FloatType&&(b.anisotropy>1||b.__oldAnisotropy)&&(Kb.texParameterf(a,Ob.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(b.anisotropy,Ac)),b.__oldAnisotropy=b.anisotropy) -}function nb(a,b){if(a.width<=b&&a.height<=b)return a;var c=Math.max(a.width,a.height),d=Math.floor(a.width*b/c),e=Math.floor(a.height*b/c),f=document.createElement("canvas");f.width=d,f.height=e;var g=f.getContext("2d");return g.drawImage(a,0,0,a.width,a.height,0,0,d,e),f}function ob(a,b){if(6===a.image.length)if(a.needsUpdate){a.image.__webglTextureCube||(a.addEventListener("dispose",Kc),a.image.__webglTextureCube=Kb.createTexture(),Qb.info.memory.textures++),Kb.activeTexture(Kb.TEXTURE0+b),Kb.bindTexture(Kb.TEXTURE_CUBE_MAP,a.image.__webglTextureCube),Kb.pixelStorei(Kb.UNPACK_FLIP_Y_WEBGL,a.flipY);for(var c=a instanceof e.CompressedTexture,d=[],f=0;6>f;f++)d[f]=Qb.autoScaleCubemaps&&!c?nb(a.image[f],zc):a.image[f];var g=d[0],h=e.Math.isPowerOfTwo(g.width)&&e.Math.isPowerOfTwo(g.height),i=ub(a.format),j=ub(a.type);mb(Kb.TEXTURE_CUBE_MAP,a,h);for(var f=0;6>f;f++)if(c)for(var k,l=d[f].mipmaps,m=0,n=l.length;n>m;m++)k=l[m],a.format!==e.RGBAFormat?Kb.compressedTexImage2D(Kb.TEXTURE_CUBE_MAP_POSITIVE_X+f,m,i,k.width,k.height,0,k.data):Kb.texImage2D(Kb.TEXTURE_CUBE_MAP_POSITIVE_X+f,m,i,k.width,k.height,0,i,j,k.data);else Kb.texImage2D(Kb.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,i,i,j,d[f]);a.generateMipmaps&&h&&Kb.generateMipmap(Kb.TEXTURE_CUBE_MAP),a.needsUpdate=!1,a.onUpdate&&a.onUpdate()}else Kb.activeTexture(Kb.TEXTURE0+b),Kb.bindTexture(Kb.TEXTURE_CUBE_MAP,a.image.__webglTextureCube)}function pb(a,b){Kb.activeTexture(Kb.TEXTURE0+b),Kb.bindTexture(Kb.TEXTURE_CUBE_MAP,a.__webglTexture)}function qb(a,b,c){Kb.bindFramebuffer(Kb.FRAMEBUFFER,a),Kb.framebufferTexture2D(Kb.FRAMEBUFFER,Kb.COLOR_ATTACHMENT0,c,b.__webglTexture,0)}function rb(a,b){Kb.bindRenderbuffer(Kb.RENDERBUFFER,a),b.depthBuffer&&!b.stencilBuffer?(Kb.renderbufferStorage(Kb.RENDERBUFFER,Kb.DEPTH_COMPONENT16,b.width,b.height),Kb.framebufferRenderbuffer(Kb.FRAMEBUFFER,Kb.DEPTH_ATTACHMENT,Kb.RENDERBUFFER,a)):b.depthBuffer&&b.stencilBuffer?(Kb.renderbufferStorage(Kb.RENDERBUFFER,Kb.DEPTH_STENCIL,b.width,b.height),Kb.framebufferRenderbuffer(Kb.FRAMEBUFFER,Kb.DEPTH_STENCIL_ATTACHMENT,Kb.RENDERBUFFER,a)):Kb.renderbufferStorage(Kb.RENDERBUFFER,Kb.RGBA4,b.width,b.height)}function sb(a){a instanceof e.WebGLRenderTargetCube?(Kb.bindTexture(Kb.TEXTURE_CUBE_MAP,a.__webglTexture),Kb.generateMipmap(Kb.TEXTURE_CUBE_MAP),Kb.bindTexture(Kb.TEXTURE_CUBE_MAP,null)):(Kb.bindTexture(Kb.TEXTURE_2D,a.__webglTexture),Kb.generateMipmap(Kb.TEXTURE_2D),Kb.bindTexture(Kb.TEXTURE_2D,null))}function tb(a){return a===e.NearestFilter||a===e.NearestMipMapNearestFilter||a===e.NearestMipMapLinearFilter?Kb.NEAREST:Kb.LINEAR}function ub(a){if(a===e.RepeatWrapping)return Kb.REPEAT;if(a===e.ClampToEdgeWrapping)return Kb.CLAMP_TO_EDGE;if(a===e.MirroredRepeatWrapping)return Kb.MIRRORED_REPEAT;if(a===e.NearestFilter)return Kb.NEAREST;if(a===e.NearestMipMapNearestFilter)return Kb.NEAREST_MIPMAP_NEAREST;if(a===e.NearestMipMapLinearFilter)return Kb.NEAREST_MIPMAP_LINEAR;if(a===e.LinearFilter)return Kb.LINEAR;if(a===e.LinearMipMapNearestFilter)return Kb.LINEAR_MIPMAP_NEAREST;if(a===e.LinearMipMapLinearFilter)return Kb.LINEAR_MIPMAP_LINEAR;if(a===e.UnsignedByteType)return Kb.UNSIGNED_BYTE;if(a===e.UnsignedShort4444Type)return Kb.UNSIGNED_SHORT_4_4_4_4;if(a===e.UnsignedShort5551Type)return Kb.UNSIGNED_SHORT_5_5_5_1;if(a===e.UnsignedShort565Type)return Kb.UNSIGNED_SHORT_5_6_5;if(a===e.ByteType)return Kb.BYTE;if(a===e.ShortType)return Kb.SHORT;if(a===e.UnsignedShortType)return Kb.UNSIGNED_SHORT;if(a===e.IntType)return Kb.INT;if(a===e.UnsignedIntType)return Kb.UNSIGNED_INT;if(a===e.FloatType)return Kb.FLOAT;if(a===e.AlphaFormat)return Kb.ALPHA;if(a===e.RGBFormat)return Kb.RGB;if(a===e.RGBAFormat)return Kb.RGBA;if(a===e.LuminanceFormat)return Kb.LUMINANCE;if(a===e.LuminanceAlphaFormat)return Kb.LUMINANCE_ALPHA;if(a===e.AddEquation)return Kb.FUNC_ADD;if(a===e.SubtractEquation)return Kb.FUNC_SUBTRACT;if(a===e.ReverseSubtractEquation)return Kb.FUNC_REVERSE_SUBTRACT;if(a===e.ZeroFactor)return Kb.ZERO;if(a===e.OneFactor)return Kb.ONE;if(a===e.SrcColorFactor)return Kb.SRC_COLOR;if(a===e.OneMinusSrcColorFactor)return Kb.ONE_MINUS_SRC_COLOR;if(a===e.SrcAlphaFactor)return Kb.SRC_ALPHA;if(a===e.OneMinusSrcAlphaFactor)return Kb.ONE_MINUS_SRC_ALPHA;if(a===e.DstAlphaFactor)return Kb.DST_ALPHA;if(a===e.OneMinusDstAlphaFactor)return Kb.ONE_MINUS_DST_ALPHA;if(a===e.DstColorFactor)return Kb.DST_COLOR;if(a===e.OneMinusDstColorFactor)return Kb.ONE_MINUS_DST_COLOR;if(a===e.SrcAlphaSaturateFactor)return Kb.SRC_ALPHA_SATURATE;if(void 0!==Pb){if(a===e.RGB_S3TC_DXT1_Format)return Pb.COMPRESSED_RGB_S3TC_DXT1_EXT;if(a===e.RGBA_S3TC_DXT1_Format)return Pb.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(a===e.RGBA_S3TC_DXT3_Format)return Pb.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(a===e.RGBA_S3TC_DXT5_Format)return Pb.COMPRESSED_RGBA_S3TC_DXT5_EXT}return 0}function vb(a){if(Cc&&a&&a.useVertexTexture)return 1024;var b=Kb.getParameter(Kb.MAX_VERTEX_UNIFORM_VECTORS),c=Math.floor((b-20)/4),d=c;return void 0!==a&&a instanceof e.SkinnedMesh&&(d=Math.min(a.bones.length,d),dg;g++){var i=a[g];i.onlyShadow||i.visible===!1||(i instanceof e.DirectionalLight&&b++,i instanceof e.PointLight&&c++,i instanceof e.SpotLight&&d++,i instanceof e.HemisphereLight&&f++)}return{directional:b,point:c,spot:d,hemi:f}}function xb(a){for(var b=0,c=0,d=a.length;d>c;c++){var f=a[c];f.castShadow&&(f instanceof e.SpotLight&&b++,f instanceof e.DirectionalLight&&!f.shadowCascade&&b++)}return b}function yb(){try{var a={alpha:Db,premultipliedAlpha:Eb,antialias:Fb,stencil:Gb,preserveDrawingBuffer:Hb};if(Kb=Bb||Ab.getContext("webgl",a)||Ab.getContext("experimental-webgl",a),null===Kb)throw"Error creating WebGL context."}catch(b){console.error(b)}Lb=Kb.getExtension("OES_texture_float"),Mb=Kb.getExtension("OES_texture_float_linear"),Nb=Kb.getExtension("OES_standard_derivatives"),Ob=Kb.getExtension("EXT_texture_filter_anisotropic")||Kb.getExtension("MOZ_EXT_texture_filter_anisotropic")||Kb.getExtension("WEBKIT_EXT_texture_filter_anisotropic"),Pb=Kb.getExtension("WEBGL_compressed_texture_s3tc")||Kb.getExtension("MOZ_WEBGL_compressed_texture_s3tc")||Kb.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc"),Lb||console.log("THREE.WebGLRenderer: Float textures not supported."),Nb||console.log("THREE.WebGLRenderer: Standard derivatives not supported."),Ob||console.log("THREE.WebGLRenderer: Anisotropic texture filtering not supported."),Pb||console.log("THREE.WebGLRenderer: S3TC compressed textures not supported."),void 0===Kb.getShaderPrecisionFormat&&(Kb.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}})}function zb(){Kb.clearColor(0,0,0,1),Kb.clearDepth(1),Kb.clearStencil(0),Kb.enable(Kb.DEPTH_TEST),Kb.depthFunc(Kb.LEQUAL),Kb.frontFace(Kb.CCW),Kb.cullFace(Kb.BACK),Kb.enable(Kb.CULL_FACE),Kb.enable(Kb.BLEND),Kb.blendEquation(Kb.FUNC_ADD),Kb.blendFunc(Kb.SRC_ALPHA,Kb.ONE_MINUS_SRC_ALPHA),Kb.viewport(jc,kc,lc,mc),Kb.clearColor(Ib.r,Ib.g,Ib.b,Jb)}console.log("THREE.WebGLRenderer",e.REVISION),a=a||{};var Ab=void 0!==a.canvas?a.canvas:document.createElement("canvas"),Bb=void 0!==a.context?a.context:null,Cb=void 0!==a.precision?a.precision:"highp",Db=void 0!==a.alpha?a.alpha:!1,Eb=void 0!==a.premultipliedAlpha?a.premultipliedAlpha:!0,Fb=void 0!==a.antialias?a.antialias:!1,Gb=void 0!==a.stencil?a.stencil:!0,Hb=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,Ib=new e.Color(0),Jb=0;this.domElement=Ab,this.context=null,this.devicePixelRatio=void 0!==a.devicePixelRatio?a.devicePixelRatio:void 0!==d.devicePixelRatio?d.devicePixelRatio:1,this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.autoUpdateObjects=!0,this.gammaInput=!1,this.gammaOutput=!1,this.shadowMapEnabled=!1,this.shadowMapAutoUpdate=!0,this.shadowMapType=e.PCFShadowMap,this.shadowMapCullFace=e.CullFaceFront,this.shadowMapDebug=!1,this.shadowMapCascade=!1,this.maxMorphTargets=8,this.maxMorphNormals=4,this.autoScaleCubemaps=!0,this.renderPluginsPre=[],this.renderPluginsPost=[],this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}};var Kb,Lb,Mb,Nb,Ob,Pb,Qb=this,Rb=[],Sb=0,Tb=null,Ub=null,Vb=-1,Wb=null,Xb=null,Yb=0,Zb=-1,$b=-1,_b=-1,ac=-1,bc=-1,cc=-1,dc=-1,ec=-1,fc=null,gc=null,hc=null,ic=null,jc=0,kc=0,lc=Ab.width,mc=Ab.height,nc=0,oc=0,pc=new Uint8Array(16),qc=new e.Frustum,rc=new e.Matrix4,sc=new e.Matrix4,tc=new e.Vector3,uc=new e.Vector3,vc=!0,wc={ambient:[0,0,0],directional:{length:0,colors:new Array,positions:new Array},point:{length:0,colors:new Array,positions:new Array,distances:new Array},spot:{length:0,colors:new Array,positions:new Array,distances:new Array,directions:new Array,anglesCos:new Array,exponents:new Array},hemi:{length:0,skyColors:new Array,groundColors:new Array,positions:new Array}};yb(),zb(),this.context=Kb;var xc=Kb.getParameter(Kb.MAX_TEXTURE_IMAGE_UNITS),yc=Kb.getParameter(Kb.MAX_VERTEX_TEXTURE_IMAGE_UNITS),zc=(Kb.getParameter(Kb.MAX_TEXTURE_SIZE),Kb.getParameter(Kb.MAX_CUBE_MAP_TEXTURE_SIZE)),Ac=Ob?Kb.getParameter(Ob.MAX_TEXTURE_MAX_ANISOTROPY_EXT):0,Bc=yc>0,Cc=Bc&&Lb,Dc=(Pb?Kb.getParameter(Kb.COMPRESSED_TEXTURE_FORMATS):[],Kb.getShaderPrecisionFormat(Kb.VERTEX_SHADER,Kb.HIGH_FLOAT)),Ec=Kb.getShaderPrecisionFormat(Kb.VERTEX_SHADER,Kb.MEDIUM_FLOAT),Fc=(Kb.getShaderPrecisionFormat(Kb.VERTEX_SHADER,Kb.LOW_FLOAT),Kb.getShaderPrecisionFormat(Kb.FRAGMENT_SHADER,Kb.HIGH_FLOAT)),Gc=Kb.getShaderPrecisionFormat(Kb.FRAGMENT_SHADER,Kb.MEDIUM_FLOAT),Hc=(Kb.getShaderPrecisionFormat(Kb.FRAGMENT_SHADER,Kb.LOW_FLOAT),Kb.getShaderPrecisionFormat(Kb.VERTEX_SHADER,Kb.HIGH_INT),Kb.getShaderPrecisionFormat(Kb.VERTEX_SHADER,Kb.MEDIUM_INT),Kb.getShaderPrecisionFormat(Kb.VERTEX_SHADER,Kb.LOW_INT),Kb.getShaderPrecisionFormat(Kb.FRAGMENT_SHADER,Kb.HIGH_INT),Kb.getShaderPrecisionFormat(Kb.FRAGMENT_SHADER,Kb.MEDIUM_INT),Kb.getShaderPrecisionFormat(Kb.FRAGMENT_SHADER,Kb.LOW_INT),Dc.precision>0&&Fc.precision>0),Ic=Ec.precision>0&&Gc.precision>0;"highp"!==Cb||Hc||(Ic?(Cb="mediump",console.warn("WebGLRenderer: highp not supported, using mediump")):(Cb="lowp",console.warn("WebGLRenderer: highp and mediump not supported, using lowp"))),"mediump"!==Cb||Ic||(Cb="lowp",console.warn("WebGLRenderer: mediump not supported, using lowp")),this.getContext=function(){return Kb},this.supportsVertexTextures=function(){return Bc},this.supportsFloatTextures=function(){return Lb},this.supportsStandardDerivatives=function(){return Nb},this.supportsCompressedTextureS3TC=function(){return Pb},this.getMaxAnisotropy=function(){return Ac},this.getPrecision=function(){return Cb},this.setSize=function(a,b,c){Ab.width=a*this.devicePixelRatio,Ab.height=b*this.devicePixelRatio,1!==this.devicePixelRatio&&c!==!1&&(Ab.style.width=a+"px",Ab.style.height=b+"px"),this.setViewport(0,0,a,b)},this.setViewport=function(a,b,c,d){jc=a*this.devicePixelRatio,kc=b*this.devicePixelRatio,lc=c*this.devicePixelRatio,mc=d*this.devicePixelRatio,Kb.viewport(jc,kc,lc,mc)},this.setScissor=function(a,b,c,d){Kb.scissor(a*this.devicePixelRatio,b*this.devicePixelRatio,c*this.devicePixelRatio,d*this.devicePixelRatio)},this.enableScissorTest=function(a){a?Kb.enable(Kb.SCISSOR_TEST):Kb.disable(Kb.SCISSOR_TEST)},this.setClearColor=function(a,b){Ib.set(a),Jb=void 0!==b?b:1,Kb.clearColor(Ib.r,Ib.g,Ib.b,Jb)},this.setClearColorHex=function(a,b){console.warn("DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead."),this.setClearColor(a,b)},this.getClearColor=function(){return Ib},this.getClearAlpha=function(){return Jb},this.clear=function(a,b,c){var d=0;(void 0===a||a)&&(d|=Kb.COLOR_BUFFER_BIT),(void 0===b||b)&&(d|=Kb.DEPTH_BUFFER_BIT),(void 0===c||c)&&(d|=Kb.STENCIL_BUFFER_BIT),Kb.clear(d)},this.clearColor=function(){Kb.clear(Kb.COLOR_BUFFER_BIT)},this.clearDepth=function(){Kb.clear(Kb.DEPTH_BUFFER_BIT)},this.clearStencil=function(){Kb.clear(Kb.STENCIL_BUFFER_BIT)},this.clearTarget=function(a,b,c,d){this.setRenderTarget(a),this.clear(b,c,d)},this.addPostPlugin=function(a){a.init(this),this.renderPluginsPost.push(a)},this.addPrePlugin=function(a){a.init(this),this.renderPluginsPre.push(a)},this.updateShadowMap=function(a,b){Tb=null,_b=-1,dc=-1,ec=-1,Wb=-1,Vb=-1,vc=!0,Zb=-1,$b=-1,this.shadowMapPlugin.update(a,b)};var Jc=function(a){var b=a.target;b.removeEventListener("dispose",Jc),Oc(b)},Kc=function(a){var b=a.target;b.removeEventListener("dispose",Kc),Pc(b),Qb.info.memory.textures--},Lc=function(a){var b=a.target;b.removeEventListener("dispose",Lc),Qc(b),Qb.info.memory.textures--},Mc=function(a){var b=a.target;b.removeEventListener("dispose",Mc),Rc(b)},Nc=function(a){if(void 0!==a.__webglVertexBuffer&&Kb.deleteBuffer(a.__webglVertexBuffer),void 0!==a.__webglNormalBuffer&&Kb.deleteBuffer(a.__webglNormalBuffer),void 0!==a.__webglTangentBuffer&&Kb.deleteBuffer(a.__webglTangentBuffer),void 0!==a.__webglColorBuffer&&Kb.deleteBuffer(a.__webglColorBuffer),void 0!==a.__webglUVBuffer&&Kb.deleteBuffer(a.__webglUVBuffer),void 0!==a.__webglUV2Buffer&&Kb.deleteBuffer(a.__webglUV2Buffer),void 0!==a.__webglSkinIndicesBuffer&&Kb.deleteBuffer(a.__webglSkinIndicesBuffer),void 0!==a.__webglSkinWeightsBuffer&&Kb.deleteBuffer(a.__webglSkinWeightsBuffer),void 0!==a.__webglFaceBuffer&&Kb.deleteBuffer(a.__webglFaceBuffer),void 0!==a.__webglLineBuffer&&Kb.deleteBuffer(a.__webglLineBuffer),void 0!==a.__webglLineDistanceBuffer&&Kb.deleteBuffer(a.__webglLineDistanceBuffer),void 0!==a.__webglCustomAttributesList)for(var b in a.__webglCustomAttributesList)Kb.deleteBuffer(a.__webglCustomAttributesList[b].buffer);Qb.info.memory.geometries--},Oc=function(a){if(a.__webglInit=void 0,a instanceof e.BufferGeometry){var b=a.attributes;for(var c in b)void 0!==b[c].buffer&&Kb.deleteBuffer(b[c].buffer);Qb.info.memory.geometries--}else if(void 0!==a.geometryGroups)for(var d in a.geometryGroups){var f=a.geometryGroups[d];if(void 0!==f.numMorphTargets)for(var g=0,h=f.numMorphTargets;h>g;g++)Kb.deleteBuffer(f.__webglMorphTargetsBuffers[g]);if(void 0!==f.numMorphNormals)for(var g=0,h=f.numMorphNormals;h>g;g++)Kb.deleteBuffer(f.__webglMorphNormalsBuffers[g]);Nc(f)}else Nc(a)},Pc=function(a){if(a.image&&a.image.__webglTextureCube)Kb.deleteTexture(a.image.__webglTextureCube);else{if(!a.__webglInit)return;a.__webglInit=!1,Kb.deleteTexture(a.__webglTexture)}},Qc=function(a){if(a&&a.__webglTexture)if(Kb.deleteTexture(a.__webglTexture),a instanceof e.WebGLRenderTargetCube)for(var b=0;6>b;b++)Kb.deleteFramebuffer(a.__webglFramebuffer[b]),Kb.deleteRenderbuffer(a.__webglRenderbuffer[b]);else Kb.deleteFramebuffer(a.__webglFramebuffer),Kb.deleteRenderbuffer(a.__webglRenderbuffer)},Rc=function(a){var b=a.program;if(void 0!==b){a.program=void 0;var c,d,e,f=!1;for(c=0,d=Rb.length;d>c;c++)if(e=Rb[c],e.program===b){e.usedTimes--,0===e.usedTimes&&(f=!0);break}if(f===!0){var g=[];for(c=0,d=Rb.length;d>c;c++)e=Rb[c],e.program!==b&&g.push(e);Rb=g,Kb.deleteProgram(b),Qb.info.memory.programs--}}};this.renderBufferImmediate=function(a,b,c){if(a.hasPositions&&!a.__webglVertexBuffer&&(a.__webglVertexBuffer=Kb.createBuffer()),a.hasNormals&&!a.__webglNormalBuffer&&(a.__webglNormalBuffer=Kb.createBuffer()),a.hasUvs&&!a.__webglUvBuffer&&(a.__webglUvBuffer=Kb.createBuffer()),a.hasColors&&!a.__webglColorBuffer&&(a.__webglColorBuffer=Kb.createBuffer()),a.hasPositions&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglVertexBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,a.positionArray,Kb.DYNAMIC_DRAW),Kb.enableVertexAttribArray(b.attributes.position),Kb.vertexAttribPointer(b.attributes.position,3,Kb.FLOAT,!1,0,0)),a.hasNormals){if(Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglNormalBuffer),c.shading===e.FlatShading){var d,f,g,h,i,j,k,l,m,n,o,p,q,r,s=3*a.count;for(r=0;s>r;r+=9)q=a.normalArray,h=q[r],k=q[r+1],n=q[r+2],i=q[r+3],l=q[r+4],o=q[r+5],j=q[r+6],m=q[r+7],p=q[r+8],d=(h+i+j)/3,f=(k+l+m)/3,g=(n+o+p)/3,q[r]=d,q[r+1]=f,q[r+2]=g,q[r+3]=d,q[r+4]=f,q[r+5]=g,q[r+6]=d,q[r+7]=f,q[r+8]=g}Kb.bufferData(Kb.ARRAY_BUFFER,a.normalArray,Kb.DYNAMIC_DRAW),Kb.enableVertexAttribArray(b.attributes.normal),Kb.vertexAttribPointer(b.attributes.normal,3,Kb.FLOAT,!1,0,0)}a.hasUvs&&c.map&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglUvBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,a.uvArray,Kb.DYNAMIC_DRAW),Kb.enableVertexAttribArray(b.attributes.uv),Kb.vertexAttribPointer(b.attributes.uv,2,Kb.FLOAT,!1,0,0)),a.hasColors&&c.vertexColors!==e.NoColors&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,a.__webglColorBuffer),Kb.bufferData(Kb.ARRAY_BUFFER,a.colorArray,Kb.DYNAMIC_DRAW),Kb.enableVertexAttribArray(b.attributes.color),Kb.vertexAttribPointer(b.attributes.color,3,Kb.FLOAT,!1,0,0)),Kb.drawArrays(Kb.TRIANGLES,0,a.count),a.count=0},this.renderBufferDirect=function(a,b,c,d,f,g){if(d.visible!==!1){var h,i,j,k,l=P(a,b,c,d,g),m=l.attributes,n=f.attributes,o=!1,p=d.wireframe?1:0,q=16777215*f.id+2*l.id+p;if(q!==Wb&&(Wb=q,o=!0),o&&w(),g instanceof e.Mesh){var r=n.index;if(r){var s=f.offsets;s.length>1&&(o=!0);for(var u=0,x=s.length;x>u;u++){var y=s[u].index;if(o){for(i in m)j=m[i],h=n[i],j>=0&&(h?(k=h.itemSize,Kb.bindBuffer(Kb.ARRAY_BUFFER,h.buffer),v(j),Kb.vertexAttribPointer(j,k,Kb.FLOAT,!1,0,y*k*4)):d.defaultAttributeValues&&(2===d.defaultAttributeValues[i].length?Kb.vertexAttrib2fv(j,d.defaultAttributeValues[i]):3===d.defaultAttributeValues[i].length&&Kb.vertexAttrib3fv(j,d.defaultAttributeValues[i])));Kb.bindBuffer(Kb.ELEMENT_ARRAY_BUFFER,r.buffer)}Kb.drawElements(Kb.TRIANGLES,s[u].count,Kb.UNSIGNED_SHORT,2*s[u].start),Qb.info.render.calls++,Qb.info.render.vertices+=s[u].count,Qb.info.render.faces+=s[u].count/3}}else{if(o)for(i in m)"index"!==i&&(j=m[i],h=n[i],j>=0&&(h?(k=h.itemSize,Kb.bindBuffer(Kb.ARRAY_BUFFER,h.buffer),v(j),Kb.vertexAttribPointer(j,k,Kb.FLOAT,!1,0,0)):d.defaultAttributeValues&&d.defaultAttributeValues[i]&&(2===d.defaultAttributeValues[i].length?Kb.vertexAttrib2fv(j,d.defaultAttributeValues[i]):3===d.defaultAttributeValues[i].length&&Kb.vertexAttrib3fv(j,d.defaultAttributeValues[i]))));var z=f.attributes.position;Kb.drawArrays(Kb.TRIANGLES,0,z.array.length/3),Qb.info.render.calls++,Qb.info.render.vertices+=z.array.length/3,Qb.info.render.faces+=z.array.length/3/3}}else if(g instanceof e.ParticleSystem){if(o)for(i in m)j=m[i],h=n[i],j>=0&&(h?(k=h.itemSize,Kb.bindBuffer(Kb.ARRAY_BUFFER,h.buffer),v(j),Kb.vertexAttribPointer(j,k,Kb.FLOAT,!1,0,0)):d.defaultAttributeValues&&d.defaultAttributeValues[i]&&(2===d.defaultAttributeValues[i].length?Kb.vertexAttrib2fv(j,d.defaultAttributeValues[i]):3===d.defaultAttributeValues[i].length&&Kb.vertexAttrib3fv(j,d.defaultAttributeValues[i])));var z=n.position;Kb.drawArrays(Kb.POINTS,0,z.array.length/3),Qb.info.render.calls++,Qb.info.render.points+=z.array.length/3}else if(g instanceof e.Line){var A=g.type===e.LineStrip?Kb.LINE_STRIP:Kb.LINES;eb(d.linewidth);var r=n.index;if(r){var s=f.offsets;s.length>1&&(o=!0);for(var u=0,x=s.length;x>u;u++){var y=s[u].index;o&&(t(d,m,n,y),Kb.bindBuffer(Kb.ELEMENT_ARRAY_BUFFER,r.buffer)),Kb.drawElements(Kb.LINES,s[u].count,Kb.UNSIGNED_SHORT,2*s[u].start),Qb.info.render.calls++,Qb.info.render.vertices+=s[u].count}}else{o&&t(d,m,n,0);var z=n.position;Kb.drawArrays(A,0,z.array.length/3),Qb.info.render.calls++,Qb.info.render.points+=z.array.length}}}},this.renderBuffer=function(a,b,c,d,f,g){if(d.visible!==!1){var h,i,j,k=P(a,b,c,d,g),l=k.attributes,m=!1,n=d.wireframe?1:0,o=16777215*f.id+2*k.id+n;if(o!==Wb&&(Wb=o,m=!0),m&&w(),!d.morphTargets&&l.position>=0?m&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,f.__webglVertexBuffer),v(l.position),Kb.vertexAttribPointer(l.position,3,Kb.FLOAT,!1,0,0)):g.morphTargetBase&&x(d,f,g),m){if(f.__webglCustomAttributesList)for(i=0,j=f.__webglCustomAttributesList.length;j>i;i++)h=f.__webglCustomAttributesList[i],l[h.buffer.belongsToAttribute]>=0&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,h.buffer),v(l[h.buffer.belongsToAttribute]),Kb.vertexAttribPointer(l[h.buffer.belongsToAttribute],h.size,Kb.FLOAT,!1,0,0));l.color>=0&&(g.geometry.colors.length>0||g.geometry.faces.length>0?(Kb.bindBuffer(Kb.ARRAY_BUFFER,f.__webglColorBuffer),v(l.color),Kb.vertexAttribPointer(l.color,3,Kb.FLOAT,!1,0,0)):d.defaultAttributeValues&&Kb.vertexAttrib3fv(l.color,d.defaultAttributeValues.color)),l.normal>=0&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,f.__webglNormalBuffer),v(l.normal),Kb.vertexAttribPointer(l.normal,3,Kb.FLOAT,!1,0,0)),l.tangent>=0&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,f.__webglTangentBuffer),v(l.tangent),Kb.vertexAttribPointer(l.tangent,4,Kb.FLOAT,!1,0,0)),l.uv>=0&&(g.geometry.faceVertexUvs[0]?(Kb.bindBuffer(Kb.ARRAY_BUFFER,f.__webglUVBuffer),v(l.uv),Kb.vertexAttribPointer(l.uv,2,Kb.FLOAT,!1,0,0)):d.defaultAttributeValues&&Kb.vertexAttrib2fv(l.uv,d.defaultAttributeValues.uv)),l.uv2>=0&&(g.geometry.faceVertexUvs[1]?(Kb.bindBuffer(Kb.ARRAY_BUFFER,f.__webglUV2Buffer),v(l.uv2),Kb.vertexAttribPointer(l.uv2,2,Kb.FLOAT,!1,0,0)):d.defaultAttributeValues&&Kb.vertexAttrib2fv(l.uv2,d.defaultAttributeValues.uv2)),d.skinning&&l.skinIndex>=0&&l.skinWeight>=0&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,f.__webglSkinIndicesBuffer),v(l.skinIndex),Kb.vertexAttribPointer(l.skinIndex,4,Kb.FLOAT,!1,0,0),Kb.bindBuffer(Kb.ARRAY_BUFFER,f.__webglSkinWeightsBuffer),v(l.skinWeight),Kb.vertexAttribPointer(l.skinWeight,4,Kb.FLOAT,!1,0,0)),l.lineDistance>=0&&(Kb.bindBuffer(Kb.ARRAY_BUFFER,f.__webglLineDistanceBuffer),v(l.lineDistance),Kb.vertexAttribPointer(l.lineDistance,1,Kb.FLOAT,!1,0,0))}if(g instanceof e.Mesh)d.wireframe?(eb(d.wireframeLinewidth),m&&Kb.bindBuffer(Kb.ELEMENT_ARRAY_BUFFER,f.__webglLineBuffer),Kb.drawElements(Kb.LINES,f.__webglLineCount,Kb.UNSIGNED_SHORT,0)):(m&&Kb.bindBuffer(Kb.ELEMENT_ARRAY_BUFFER,f.__webglFaceBuffer),Kb.drawElements(Kb.TRIANGLES,f.__webglFaceCount,Kb.UNSIGNED_SHORT,0)),Qb.info.render.calls++,Qb.info.render.vertices+=f.__webglFaceCount,Qb.info.render.faces+=f.__webglFaceCount/3;else if(g instanceof e.Line){var p=g.type===e.LineStrip?Kb.LINE_STRIP:Kb.LINES;eb(d.linewidth),Kb.drawArrays(p,0,f.__webglLineCount),Qb.info.render.calls++}else g instanceof e.ParticleSystem&&(Kb.drawArrays(Kb.POINTS,0,f.__webglParticleCount),Qb.info.render.calls++,Qb.info.render.points+=f.__webglParticleCount)}},this.render=function(a,b,c,d){if(b instanceof e.Camera==!1)return void console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");var f,g,h,i,j,k=a.__lights,l=a.fog;for(Vb=-1,vc=!0,a.autoUpdate===!0&&a.updateMatrixWorld(),void 0===b.parent&&b.updateMatrixWorld(),b.matrixWorldInverse.getInverse(b.matrixWorld),rc.multiplyMatrices(b.projectionMatrix,b.matrixWorldInverse),qc.setFromMatrix(rc),this.autoUpdateObjects&&this.initWebGLObjects(a),A(this.renderPluginsPre,a,b),Qb.info.render.calls=0,Qb.info.render.vertices=0,Qb.info.render.faces=0,Qb.info.render.points=0,this.setRenderTarget(c),(this.autoClear||d)&&this.clear(this.autoClearColor,this.autoClearDepth,this.autoClearStencil),j=a.__webglObjects,f=0,g=j.length;g>f;f++)h=j[f],i=h.object,h.id=f,h.render=!1,i.visible&&((i instanceof e.Mesh||i instanceof e.ParticleSystem)&&i.frustumCulled&&!qc.intersectsObject(i)||(ab(i,b),E(h),h.render=!0,this.sortObjects===!0&&(null!==i.renderDepth?h.z=i.renderDepth:(tc.setFromMatrixPosition(i.matrixWorld),tc.applyProjection(rc),h.z=tc.z))));for(this.sortObjects&&j.sort(y),j=a.__webglObjectsImmediate,f=0,g=j.length;g>f;f++)h=j[f],i=h.object,i.visible&&(ab(i,b),D(h));if(a.overrideMaterial){var m=a.overrideMaterial;this.setBlending(m.blending,m.blendEquation,m.blendSrc,m.blendDst),this.setDepthTest(m.depthTest),this.setDepthWrite(m.depthWrite),fb(m.polygonOffset,m.polygonOffsetFactor,m.polygonOffsetUnits),B(a.__webglObjects,!1,"",b,k,l,!0,m),C(a.__webglObjectsImmediate,"",b,k,l,!1,m)}else{var m=null;this.setBlending(e.NoBlending),B(a.__webglObjects,!0,"opaque",b,k,l,!1,m),C(a.__webglObjectsImmediate,"opaque",b,k,l,!1,m),B(a.__webglObjects,!1,"transparent",b,k,l,!0,m),C(a.__webglObjectsImmediate,"transparent",b,k,l,!0,m)}A(this.renderPluginsPost,a,b),c&&c.generateMipmaps&&c.minFilter!==e.NearestFilter&&c.minFilter!==e.LinearFilter&&sb(c),this.setDepthTest(!0),this.setDepthWrite(!0)},this.renderImmediateObject=function(a,b,c,d,e){var f=P(a,b,c,d,e);Wb=-1,Qb.setMaterialFaces(d),e.immediateRenderCallback?e.immediateRenderCallback(f,Kb,qc):e.render(function(a){Qb.renderBufferImmediate(a,f,d)})},this.initWebGLObjects=function(a){for(a.__webglObjects||(a.__webglObjects=[],a.__webglObjectsImmediate=[],a.__webglSprites=[],a.__webglFlares=[]);a.__objectsAdded.length;)F(a.__objectsAdded[0],a),a.__objectsAdded.splice(0,1);for(;a.__objectsRemoved.length;)L(a.__objectsRemoved[0],a),a.__objectsRemoved.splice(0,1);for(var b=0,c=a.__webglObjects.length;c>b;b++){var d=a.__webglObjects[b].object;void 0===d.__webglInit&&(void 0!==d.__webglActive&&L(d,a),F(d,a)),I(d)}},this.initMaterial=function(a,b,c,d){a.addEventListener("dispose",Mc);var f,g,h,i,j,k,l;a instanceof e.MeshDepthMaterial?l="depth":a instanceof e.MeshNormalMaterial?l="normal":a instanceof e.MeshBasicMaterial?l="basic":a instanceof e.MeshLambertMaterial?l="lambert":a instanceof e.MeshPhongMaterial?l="phong":a instanceof e.LineBasicMaterial?l="basic":a instanceof e.LineDashedMaterial?l="dashed":a instanceof e.ParticleSystemMaterial&&(l="particle_basic"),l&&O(a,e.ShaderLib[l]),i=wb(b),k=xb(b),j=vb(d),h={map:!!a.map,envMap:!!a.envMap,lightMap:!!a.lightMap,bumpMap:!!a.bumpMap,normalMap:!!a.normalMap,specularMap:!!a.specularMap,vertexColors:a.vertexColors,fog:c,useFog:a.fog,fogExp:c instanceof e.FogExp2,sizeAttenuation:a.sizeAttenuation,skinning:a.skinning,maxBones:j,useVertexTexture:Cc&&d&&d.useVertexTexture,morphTargets:a.morphTargets,morphNormals:a.morphNormals,maxMorphTargets:this.maxMorphTargets,maxMorphNormals:this.maxMorphNormals,maxDirLights:i.directional,maxPointLights:i.point,maxSpotLights:i.spot,maxHemiLights:i.hemi,maxShadows:k,shadowMapEnabled:this.shadowMapEnabled&&d.receiveShadow&&k>0,shadowMapType:this.shadowMapType,shadowMapDebug:this.shadowMapDebug,shadowMapCascade:this.shadowMapCascade,alphaTest:a.alphaTest,metal:a.metal,wrapAround:a.wrapAround,doubleSided:a.side===e.DoubleSide,flipSided:a.side===e.BackSide},a.program=hb(l,a.fragmentShader,a.vertexShader,a.uniforms,a.attributes,a.defines,h,a.index0AttributeName);var m=a.program.attributes;if(a.morphTargets){a.numSupportedMorphTargets=0;var n,o="morphTarget";for(g=0;g=0&&a.numSupportedMorphTargets++}if(a.morphNormals){a.numSupportedMorphNormals=0;var n,o="morphNormal";for(g=0;g=0&&a.numSupportedMorphNormals++}a.uniformsList=[];for(f in a.uniforms)a.uniformsList.push([a.uniforms[f],f])},this.setFaceCulling=function(a,b){a===e.CullFaceNone?Kb.disable(Kb.CULL_FACE):(Kb.frontFace(b===e.FrontFaceDirectionCW?Kb.CW:Kb.CCW),Kb.cullFace(a===e.CullFaceBack?Kb.BACK:a===e.CullFaceFront?Kb.FRONT:Kb.FRONT_AND_BACK),Kb.enable(Kb.CULL_FACE))},this.setMaterialFaces=function(a){var b=a.side===e.DoubleSide,c=a.side===e.BackSide;Zb!==b&&(b?Kb.disable(Kb.CULL_FACE):Kb.enable(Kb.CULL_FACE),Zb=b),$b!==c&&(Kb.frontFace(c?Kb.CW:Kb.CCW),$b=c)},this.setDepthTest=function(a){dc!==a&&(a?Kb.enable(Kb.DEPTH_TEST):Kb.disable(Kb.DEPTH_TEST),dc=a)},this.setDepthWrite=function(a){ec!==a&&(Kb.depthMask(a),ec=a)},this.setBlending=function(a,b,c,d){a!==_b&&(a===e.NoBlending?Kb.disable(Kb.BLEND):a===e.AdditiveBlending?(Kb.enable(Kb.BLEND),Kb.blendEquation(Kb.FUNC_ADD),Kb.blendFunc(Kb.SRC_ALPHA,Kb.ONE)):a===e.SubtractiveBlending?(Kb.enable(Kb.BLEND),Kb.blendEquation(Kb.FUNC_ADD),Kb.blendFunc(Kb.ZERO,Kb.ONE_MINUS_SRC_COLOR)):a===e.MultiplyBlending?(Kb.enable(Kb.BLEND),Kb.blendEquation(Kb.FUNC_ADD),Kb.blendFunc(Kb.ZERO,Kb.SRC_COLOR)):a===e.CustomBlending?Kb.enable(Kb.BLEND):(Kb.enable(Kb.BLEND),Kb.blendEquationSeparate(Kb.FUNC_ADD,Kb.FUNC_ADD),Kb.blendFuncSeparate(Kb.SRC_ALPHA,Kb.ONE_MINUS_SRC_ALPHA,Kb.ONE,Kb.ONE_MINUS_SRC_ALPHA)),_b=a),a===e.CustomBlending?(b!==ac&&(Kb.blendEquation(ub(b)),ac=b),(c!==bc||d!==cc)&&(Kb.blendFunc(ub(c),ub(d)),bc=c,cc=d)):(ac=null,bc=null,cc=null)},this.setTexture=function(a,b){if(a.needsUpdate){a.__webglInit||(a.__webglInit=!0,a.addEventListener("dispose",Kc),a.__webglTexture=Kb.createTexture(),Qb.info.memory.textures++),Kb.activeTexture(Kb.TEXTURE0+b),Kb.bindTexture(Kb.TEXTURE_2D,a.__webglTexture),Kb.pixelStorei(Kb.UNPACK_FLIP_Y_WEBGL,a.flipY),Kb.pixelStorei(Kb.UNPACK_PREMULTIPLY_ALPHA_WEBGL,a.premultiplyAlpha),Kb.pixelStorei(Kb.UNPACK_ALIGNMENT,a.unpackAlignment);var c=a.image,d=e.Math.isPowerOfTwo(c.width)&&e.Math.isPowerOfTwo(c.height),f=ub(a.format),g=ub(a.type);mb(Kb.TEXTURE_2D,a,d);var h,i=a.mipmaps;if(a instanceof e.DataTexture)if(i.length>0&&d){for(var j=0,k=i.length;k>j;j++)h=i[j],Kb.texImage2D(Kb.TEXTURE_2D,j,f,h.width,h.height,0,f,g,h.data);a.generateMipmaps=!1}else Kb.texImage2D(Kb.TEXTURE_2D,0,f,c.width,c.height,0,f,g,c.data);else if(a instanceof e.CompressedTexture)for(var j=0,k=i.length;k>j;j++)h=i[j],a.format!==e.RGBAFormat?Kb.compressedTexImage2D(Kb.TEXTURE_2D,j,f,h.width,h.height,0,h.data):Kb.texImage2D(Kb.TEXTURE_2D,j,f,h.width,h.height,0,f,g,h.data);else if(i.length>0&&d){for(var j=0,k=i.length;k>j;j++)h=i[j],Kb.texImage2D(Kb.TEXTURE_2D,j,f,f,g,h);a.generateMipmaps=!1}else Kb.texImage2D(Kb.TEXTURE_2D,0,f,f,g,a.image);a.generateMipmaps&&d&&Kb.generateMipmap(Kb.TEXTURE_2D),a.needsUpdate=!1,a.onUpdate&&a.onUpdate()}else Kb.activeTexture(Kb.TEXTURE0+b),Kb.bindTexture(Kb.TEXTURE_2D,a.__webglTexture)},this.setRenderTarget=function(a){var b=a instanceof e.WebGLRenderTargetCube;if(a&&!a.__webglFramebuffer){void 0===a.depthBuffer&&(a.depthBuffer=!0),void 0===a.stencilBuffer&&(a.stencilBuffer=!0),a.addEventListener("dispose",Lc),a.__webglTexture=Kb.createTexture(),Qb.info.memory.textures++;var c=e.Math.isPowerOfTwo(a.width)&&e.Math.isPowerOfTwo(a.height),d=ub(a.format),f=ub(a.type);if(b){a.__webglFramebuffer=[],a.__webglRenderbuffer=[],Kb.bindTexture(Kb.TEXTURE_CUBE_MAP,a.__webglTexture),mb(Kb.TEXTURE_CUBE_MAP,a,c);for(var g=0;6>g;g++)a.__webglFramebuffer[g]=Kb.createFramebuffer(),a.__webglRenderbuffer[g]=Kb.createRenderbuffer(),Kb.texImage2D(Kb.TEXTURE_CUBE_MAP_POSITIVE_X+g,0,d,a.width,a.height,0,d,f,null),qb(a.__webglFramebuffer[g],a,Kb.TEXTURE_CUBE_MAP_POSITIVE_X+g),rb(a.__webglRenderbuffer[g],a);c&&Kb.generateMipmap(Kb.TEXTURE_CUBE_MAP)}else a.__webglFramebuffer=Kb.createFramebuffer(),a.__webglRenderbuffer=a.shareDepthFrom?a.shareDepthFrom.__webglRenderbuffer:Kb.createRenderbuffer(),Kb.bindTexture(Kb.TEXTURE_2D,a.__webglTexture),mb(Kb.TEXTURE_2D,a,c),Kb.texImage2D(Kb.TEXTURE_2D,0,d,a.width,a.height,0,d,f,null),qb(a.__webglFramebuffer,a,Kb.TEXTURE_2D),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?Kb.framebufferRenderbuffer(Kb.FRAMEBUFFER,Kb.DEPTH_ATTACHMENT,Kb.RENDERBUFFER,a.__webglRenderbuffer):a.depthBuffer&&a.stencilBuffer&&Kb.framebufferRenderbuffer(Kb.FRAMEBUFFER,Kb.DEPTH_STENCIL_ATTACHMENT,Kb.RENDERBUFFER,a.__webglRenderbuffer):rb(a.__webglRenderbuffer,a),c&&Kb.generateMipmap(Kb.TEXTURE_2D);b?Kb.bindTexture(Kb.TEXTURE_CUBE_MAP,null):Kb.bindTexture(Kb.TEXTURE_2D,null),Kb.bindRenderbuffer(Kb.RENDERBUFFER,null),Kb.bindFramebuffer(Kb.FRAMEBUFFER,null)}var h,i,j,k,l;a?(h=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,i=a.width,j=a.height,k=0,l=0):(h=null,i=lc,j=mc,k=jc,l=kc),h!==Ub&&(Kb.bindFramebuffer(Kb.FRAMEBUFFER,h),Kb.viewport(k,l,i,j),Ub=h),nc=i,oc=j},this.shadowMapPlugin=new e.ShadowMapPlugin,this.addPrePlugin(this.shadowMapPlugin),this.addPostPlugin(new e.SpritePlugin),this.addPostPlugin(new e.LensFlarePlugin)},e.WebGLRenderTarget=function(a,b,c){this.width=a,this.height=b,c=c||{},this.wrapS=void 0!==c.wrapS?c.wrapS:e.ClampToEdgeWrapping,this.wrapT=void 0!==c.wrapT?c.wrapT:e.ClampToEdgeWrapping,this.magFilter=void 0!==c.magFilter?c.magFilter:e.LinearFilter,this.minFilter=void 0!==c.minFilter?c.minFilter:e.LinearMipMapLinearFilter,this.anisotropy=void 0!==c.anisotropy?c.anisotropy:1,this.offset=new e.Vector2(0,0),this.repeat=new e.Vector2(1,1),this.format=void 0!==c.format?c.format:e.RGBAFormat,this.type=void 0!==c.type?c.type:e.UnsignedByteType,this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0,this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0,this.generateMipmaps=!0,this.shareDepthFrom=null -},e.WebGLRenderTarget.prototype={constructor:e.WebGLRenderTarget,clone:function(){var a=new e.WebGLRenderTarget(this.width,this.height);return a.wrapS=this.wrapS,a.wrapT=this.wrapT,a.magFilter=this.magFilter,a.minFilter=this.minFilter,a.anisotropy=this.anisotropy,a.offset.copy(this.offset),a.repeat.copy(this.repeat),a.format=this.format,a.type=this.type,a.depthBuffer=this.depthBuffer,a.stencilBuffer=this.stencilBuffer,a.generateMipmaps=this.generateMipmaps,a.shareDepthFrom=this.shareDepthFrom,a},dispose:function(){this.dispatchEvent({type:"dispose"})}},e.EventDispatcher.prototype.apply(e.WebGLRenderTarget.prototype),e.WebGLRenderTargetCube=function(a,b,c){e.WebGLRenderTarget.call(this,a,b,c),this.activeCubeFace=0},e.WebGLRenderTargetCube.prototype=Object.create(e.WebGLRenderTarget.prototype),e.RenderableVertex=function(){this.position=new e.Vector3,this.positionWorld=new e.Vector3,this.positionScreen=new e.Vector4,this.visible=!0},e.RenderableVertex.prototype.copy=function(a){this.positionWorld.copy(a.positionWorld),this.positionScreen.copy(a.positionScreen)},e.RenderableFace=function(){this.id=0,this.v1=new e.RenderableVertex,this.v2=new e.RenderableVertex,this.v3=new e.RenderableVertex,this.centroidModel=new e.Vector3,this.normalModel=new e.Vector3,this.vertexNormalsModel=[new e.Vector3,new e.Vector3,new e.Vector3],this.vertexNormalsLength=0,this.color=null,this.material=null,this.uvs=[[]],this.z=0},e.RenderableObject=function(){this.id=0,this.object=null,this.z=0},e.RenderableSprite=function(){this.id=0,this.object=null,this.x=0,this.y=0,this.z=0,this.rotation=0,this.scale=new e.Vector2,this.material=null},e.RenderableLine=function(){this.id=0,this.v1=new e.RenderableVertex,this.v2=new e.RenderableVertex,this.vertexColors=[new e.Color,new e.Color],this.material=null,this.z=0},e.GeometryUtils={merge:function(a,b,c){var d,f,g=a.vertices.length,h=(a.faceVertexUvs[0].length,b instanceof e.Mesh?b.geometry:b),i=a.vertices,j=h.vertices,k=a.faces,l=h.faces,m=a.faceVertexUvs[0],n=h.faceVertexUvs[0];void 0===c&&(c=0),b instanceof e.Mesh&&(b.matrixAutoUpdate&&b.updateMatrix(),d=b.matrix,f=(new e.Matrix3).getNormalMatrix(d));for(var o=0,p=j.length;p>o;o++){var q=j[o],r=q.clone();d&&r.applyMatrix4(d),i.push(r)}for(o=0,p=l.length;p>o;o++){var s,t,u,v=l[o],w=v.vertexNormals,x=v.vertexColors;s=new e.Face3(v.a+g,v.b+g,v.c+g),s.normal.copy(v.normal),f&&s.normal.applyMatrix3(f).normalize();for(var y=0,z=w.length;z>y;y++)t=w[y].clone(),f&&t.applyMatrix3(f).normalize(),s.vertexNormals.push(t);s.color.copy(v.color);for(var y=0,z=x.length;z>y;y++)u=x[y],s.vertexColors.push(u.clone());s.materialIndex=v.materialIndex+c,s.centroid.copy(v.centroid),d&&s.centroid.applyMatrix4(d),k.push(s)}for(o=0,p=n.length;p>o;o++){for(var A=n[o],B=[],y=0,z=A.length;z>y;y++)B.push(new e.Vector2(A[y].x,A[y].y));m.push(B)}},randomPointInTriangle:function(){var a=new e.Vector3;return function(b,c,d){var f=new e.Vector3,g=e.Math.random16(),h=e.Math.random16();g+h>1&&(g=1-g,h=1-h);var i=1-g-h;return f.copy(b),f.multiplyScalar(g),a.copy(c),a.multiplyScalar(h),f.add(a),a.copy(d),a.multiplyScalar(i),f.add(a),f}}(),randomPointInFace:function(a,b){var c,d,f;return c=b.vertices[a.a],d=b.vertices[a.b],f=b.vertices[a.c],e.GeometryUtils.randomPointInTriangle(c,d,f)},randomPointsInGeometry:function(a,b){function c(a){function b(c,d){if(c>d)return c;var e=c+Math.floor((d-c)/2);return n[e]>a?b(c,e-1):n[e]f;f++)d=j[f],g=k[d.a],h=k[d.b],i=k[d.c],d._area=e.GeometryUtils.triangleArea(g,h,i),m+=d._area,n[f]=m;var o,p,q=[],r={};for(f=0;b>f;f++)o=e.Math.random16()*m,p=c(o),q[f]=e.GeometryUtils.randomPointInFace(j[p],a,!0),r[p]?r[p]+=1:r[p]=1;return q},triangleArea:function(){var a=new e.Vector3,b=new e.Vector3;return function(c,d,e){return a.subVectors(d,c),b.subVectors(e,c),a.cross(b),.5*a.length()}}(),center:function(a){a.computeBoundingBox();var b=a.boundingBox,c=new e.Vector3;return c.addVectors(b.min,b.max),c.multiplyScalar(-.5),a.applyMatrix((new e.Matrix4).makeTranslation(c.x,c.y,c.z)),a.computeBoundingBox(),c},triangulateQuads:function(a){var b,c,d,e,f=[],g=[];for(b=0,c=a.faceVertexUvs.length;c>b;b++)g[b]=[];for(b=0,c=a.faces.length;c>b;b++){var h=a.faces[b];for(f.push(h),d=0,e=a.faceVertexUvs.length;e>d;d++)g[d].push(a.faceVertexUvs[d][b])}a.faces=f,a.faceVertexUvs=g,a.computeCentroids(),a.computeFaceNormals(),a.computeVertexNormals(),a.hasTangents&&a.computeTangents()}},e.ImageUtils={crossOrigin:void 0,loadTexture:function(a,b,c){var d=new e.ImageLoader;d.crossOrigin=this.crossOrigin;var f=new e.Texture(void 0,b),g=d.load(a,function(){f.needsUpdate=!0,c&&c(f)});return f.image=g,f.sourceFile=a,f},loadCompressedTexture:function(a,b,c,d){var f=new e.CompressedTexture;f.mapping=b;var g=new XMLHttpRequest;return g.onload=function(){var a=g.response,b=e.ImageUtils.parseDDS(a,!0);f.format=b.format,f.mipmaps=b.mipmaps,f.image.width=b.width,f.image.height=b.height,f.generateMipmaps=!1,f.needsUpdate=!0,c&&c(f)},g.onerror=d,g.open("GET",a,!0),g.responseType="arraybuffer",g.send(null),f},loadTextureCube:function(a,b,c,d){var f=[];f.loadCount=0;var g=new e.Texture;g.image=f,void 0!==b&&(g.mapping=b),g.flipY=!1;for(var h=0,i=a.length;i>h;++h){var j=new Image;f[h]=j,j.onload=function(){f.loadCount+=1,6===f.loadCount&&(g.needsUpdate=!0,c&&c(g))},j.onerror=d,j.crossOrigin=this.crossOrigin,j.src=a[h]}return g},loadCompressedTextureCube:function(a,b,c,d){var f=[];f.loadCount=0;var g=new e.CompressedTexture;g.image=f,void 0!==b&&(g.mapping=b),g.flipY=!1,g.generateMipmaps=!1;var h=function(a,b){return function(){var d=a.response,h=e.ImageUtils.parseDDS(d,!0);b.format=h.format,b.mipmaps=h.mipmaps,b.width=h.width,b.height=h.height,f.loadCount+=1,6===f.loadCount&&(g.format=h.format,g.needsUpdate=!0,c&&c(g))}};if(a instanceof Array)for(var i=0,j=a.length;j>i;++i){var k={};f[i]=k;var l=new XMLHttpRequest;l.onload=h(l,k),l.onerror=d;var m=a[i];l.open("GET",m,!0),l.responseType="arraybuffer",l.send(null)}else{var m=a,l=new XMLHttpRequest;l.onload=function(){var a=l.response,b=e.ImageUtils.parseDDS(a,!0);if(b.isCubemap){for(var d=b.mipmaps.length/b.mipmapCount,h=0;d>h;h++){f[h]={mipmaps:[]};for(var i=0;ii;i++){f[i]={mipmaps:[]};for(var j=0;j>8&255,a>>16&255,a>>24&255)}function f(a,b,c,d){for(var e=c*d*4,f=new Uint8Array(a,b,e),g=new Uint8Array(e),h=0,i=0,j=0;d>j;j++)for(var k=0;c>k;k++){var l=f[i];i++;var m=f[i];i++;var n=f[i];i++;var o=f[i];i++,g[h]=n,h++,g[h]=m,h++,g[h]=l,h++,g[h]=o,h++}return g}var g={mipmaps:[],width:0,height:0,format:null,mipmapCount:1},h=542327876,i=131072,j=512,k=4,l=c("DXT1"),m=c("DXT3"),n=c("DXT5"),o=31,p=0,q=1,r=2,s=3,t=4,u=7,v=20,w=21,x=22,y=23,z=24,A=25,B=26,C=28,D=new Int32Array(a,0,o);if(D[p]!==h)return console.error("ImageUtils.parseDDS(): Invalid magic number in DDS header"),g;if(!D[v]&k)return console.error("ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code"),g;var E,F=D[w],G=!1;switch(F){case l:E=8,g.format=e.RGB_S3TC_DXT1_Format;break;case m:E=16,g.format=e.RGBA_S3TC_DXT3_Format;break;case n:E=16,g.format=e.RGBA_S3TC_DXT5_Format;break;default:if(!(32==D[x]&&16711680&D[y]&&65280&D[z]&&255&D[A]&&4278190080&D[B]))return console.error("ImageUtils.parseDDS(): Unsupported FourCC code: ",d(F)),g;G=!0,E=64,g.format=e.RGBAFormat}g.mipmapCount=1,D[r]&i&&b!==!1&&(g.mipmapCount=Math.max(1,D[u])),g.isCubemap=D[C]&j?!0:!1,g.width=D[t],g.height=D[s];for(var H=D[q]+4,I=g.width,J=g.height,K=g.isCubemap?6:1,L=0;K>L;L++){for(var M=0;Mm;m++)for(var n=0;g>n;n++){var o=0>n-1?0:n-1,p=n+1>g-1?g-1:n+1,q=0>m-1?0:m-1,r=m+1>f-1?f-1:m+1,s=[],t=[0,0,j[4*(n*f+m)]/255*b];s.push([-1,0,j[4*(n*f+q)]/255*b]),s.push([-1,-1,j[4*(o*f+q)]/255*b]),s.push([0,-1,j[4*(o*f+m)]/255*b]),s.push([1,-1,j[4*(o*f+r)]/255*b]),s.push([1,0,j[4*(n*f+r)]/255*b]),s.push([1,1,j[4*(p*f+r)]/255*b]),s.push([0,1,j[4*(p*f+m)]/255*b]),s.push([-1,1,j[4*(p*f+q)]/255*b]);for(var u=[],v=s.length,w=0;v>w;w++){var x=s[w],y=s[(w+1)%v];x=d(x,t),y=d(y,t),u.push(e(c(x,y)))}for(var z=[0,0,0],w=0;wj;j++)f[3*j]=g,f[3*j+1]=h,f[3*j+2]=i;var k=new e.DataTexture(f,a,b,e.RGBFormat);return k.needsUpdate=!0,k}},e.SceneUtils={createMultiMaterialObject:function(a,b){for(var c=new e.Object3D,d=0,f=b.length;f>d;d++)c.add(new e.Mesh(a,b[d]));return c},detach:function(a,b,c){a.applyMatrix(b.matrixWorld),b.remove(a),c.add(a)},attach:function(a,b,c){var d=new e.Matrix4;d.getInverse(c.matrixWorld),a.applyMatrix(d),b.remove(a),c.add(a)}},e.FontUtils={faces:{},face:"helvetiker",weight:"normal",style:"normal",size:150,divisions:10,getFace:function(){return this.faces[this.face][this.weight][this.style]},loadFace:function(a){var b=a.familyName.toLowerCase(),c=this;c.faces[b]=c.faces[b]||{},c.faces[b][a.cssFontWeight]=c.faces[b][a.cssFontWeight]||{},c.faces[b][a.cssFontWeight][a.cssFontStyle]=a;c.faces[b][a.cssFontWeight][a.cssFontStyle]=a;return a},drawText:function(a){var b,c=this.getFace(),d=this.size/c.resolution,f=0,g=String(a).split(""),h=g.length,i=[];for(b=0;h>b;b++){var j=new e.Path,k=this.extractGlyphPoints(g[b],c,d,f,j);f+=k.offset,i.push(k.path)}var l=f/2;return{paths:i,offset:l}},extractGlyphPoints:function(a,b,c,d,f){var g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z=[],A=b.glyphs[a]||b.glyphs["?"];if(A){if(A.o)for(j=A._cachedOutline||(A._cachedOutline=A.o.split(" ")),l=j.length,m=c,n=c,g=0;l>g;)switch(k=j[g++]){case"m":o=j[g++]*m+d,p=j[g++]*n,f.moveTo(o,p);break;case"l":o=j[g++]*m+d,p=j[g++]*n,f.lineTo(o,p);break;case"q":if(q=j[g++]*m+d,r=j[g++]*n,u=j[g++]*m+d,v=j[g++]*n,f.quadraticCurveTo(u,v,q,r),y=z[z.length-1])for(s=y.x,t=y.y,h=1,i=this.divisions;i>=h;h++){var B=h/i;e.Shape.Utils.b2(B,s,u,q),e.Shape.Utils.b2(B,t,v,r)}break;case"b":if(q=j[g++]*m+d,r=j[g++]*n,u=j[g++]*m+d,v=j[g++]*-n,w=j[g++]*m+d,x=j[g++]*-n,f.bezierCurveTo(q,r,u,v,w,x),y=z[z.length-1])for(s=y.x,t=y.y,h=1,i=this.divisions;i>=h;h++){var B=h/i;e.Shape.Utils.b3(B,s,u,w,q),e.Shape.Utils.b3(B,t,v,x,r)}}return{offset:A.ha*c,path:f}}}},e.FontUtils.generateShapes=function(a,b){b=b||{};var c=void 0!==b.size?b.size:100,d=void 0!==b.curveSegments?b.curveSegments:4,f=void 0!==b.font?b.font:"helvetiker",g=void 0!==b.weight?b.weight:"normal",h=void 0!==b.style?b.style:"normal";e.FontUtils.size=c,e.FontUtils.divisions=d,e.FontUtils.face=f,e.FontUtils.weight=g,e.FontUtils.style=h;for(var i=e.FontUtils.drawText(a),j=i.paths,k=[],l=0,m=j.length;m>l;l++)Array.prototype.push.apply(k,j[l].toShapes());return k},function(a){var b=1e-10,c=function(a,b){var c=a.length;if(3>c)return null;var f,g,h,i=[],j=[],k=[];if(d(a)>0)for(g=0;c>g;g++)j[g]=g;else for(g=0;c>g;g++)j[g]=c-1-g;var l=c,m=2*l;for(g=l-1;l>2;){if(m--<=0)return console.log("Warning, unable to triangulate polygon!"),b?k:i;if(f=g,f>=l&&(f=0),g=f+1,g>=l&&(g=0),h=g+1,h>=l&&(h=0),e(a,f,g,h,l,j)){var n,o,p,q,r;for(n=j[f],o=j[g],p=j[h],i.push([a[n],a[o],a[p]]),k.push([j[f],j[g],j[h]]),q=g,r=g+1;l>r;q++,r++)j[q]=j[r];l--,m=2*l}}return b?k:i},d=function(a){for(var b=a.length,c=0,d=b-1,e=0;b>e;d=e++)c+=a[d].x*a[e].y-a[e].x*a[d].y;return.5*c},e=function(a,c,d,e,f,g){var h,i,j,k,l,m,n,o,p;if(i=a[g[c]].x,j=a[g[c]].y,k=a[g[d]].x,l=a[g[d]].y,m=a[g[e]].x,n=a[g[e]].y,b>(k-i)*(n-j)-(l-j)*(m-i))return!1;var q,r,s,t,u,v,w,x,y,z,A,B,C,D,E;for(q=m-k,r=n-l,s=i-m,t=j-n,u=k-i,v=l-j,h=0;f>h;h++)if(o=a[g[h]].x,p=a[g[h]].y,!(o===i&&p===j||o===k&&p===l||o===m&&p===n)&&(w=o-i,x=p-j,y=o-k,z=p-l,A=o-m,B=p-n,E=q*z-r*y,C=u*x-v*w,D=s*B-t*A,E>=-b&&D>=-b&&C>=-b))return!1;return!0};return a.Triangulate=c,a.Triangulate.area=d,a}(e.FontUtils),d._typeface_js={faces:e.FontUtils.faces,loadFace:e.FontUtils.loadFace},e.typeface_js=d._typeface_js,e.Curve=function(){},e.Curve.prototype.getPoint=function(){return console.log("Warning, getPoint() not implemented!"),null},e.Curve.prototype.getPointAt=function(a){var b=this.getUtoTmapping(a);return this.getPoint(b)},e.Curve.prototype.getPoints=function(a){a||(a=5);var b,c=[];for(b=0;a>=b;b++)c.push(this.getPoint(b/a));return c},e.Curve.prototype.getSpacedPoints=function(a){a||(a=5);var b,c=[];for(b=0;a>=b;b++)c.push(this.getPointAt(b/a));return c},e.Curve.prototype.getLength=function(){var a=this.getLengths();return a[a.length-1]},e.Curve.prototype.getLengths=function(a){if(a||(a=this.__arcLengthDivisions?this.__arcLengthDivisions:200),this.cacheArcLengths&&this.cacheArcLengths.length==a+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;var b,c,d=[],e=this.getPoint(0),f=0;for(d.push(0),c=1;a>=c;c++)b=this.getPoint(c/a),f+=b.distanceTo(e),d.push(f),e=b;return this.cacheArcLengths=d,d},e.Curve.prototype.updateArcLengths=function(){this.needsUpdate=!0,this.getLengths()},e.Curve.prototype.getUtoTmapping=function(a,b){var c,d=this.getLengths(),e=0,f=d.length;c=b?b:a*d[f-1];for(var g,h=0,i=f-1;i>=h;)if(e=Math.floor(h+(i-h)/2),g=d[e]-c,0>g)h=e+1;else{if(!(g>0)){i=e;break}i=e-1}if(e=i,d[e]==c){var j=e/(f-1);return j}var k=d[e],l=d[e+1],m=l-k,n=(c-k)/m,j=(e+n)/(f-1);return j},e.Curve.prototype.getTangent=function(a){var b=1e-4,c=a-b,d=a+b;0>c&&(c=0),d>1&&(d=1);var e=this.getPoint(c),f=this.getPoint(d),g=f.clone().sub(e);return g.normalize()},e.Curve.prototype.getTangentAt=function(a){var b=this.getUtoTmapping(a);return this.getTangent(b)},e.Curve.Utils={tangentQuadraticBezier:function(a,b,c,d){return 2*(1-a)*(c-b)+2*a*(d-c)},tangentCubicBezier:function(a,b,c,d,e){return-3*b*(1-a)*(1-a)+3*c*(1-a)*(1-a)-6*a*c*(1-a)+6*a*d*(1-a)-3*a*a*d+3*a*a*e},tangentSpline:function(a){var b=6*a*a-6*a,c=3*a*a-4*a+1,d=-6*a*a+6*a,e=3*a*a-2*a;return b+c+d+e},interpolate:function(a,b,c,d,e){var f=.5*(c-a),g=.5*(d-b),h=e*e,i=e*h;return(2*b-2*c+f+g)*i+(-3*b+3*c-2*f-g)*h+f*e+b}},e.Curve.create=function(a,b){return a.prototype=Object.create(e.Curve.prototype),a.prototype.getPoint=b,a},e.CurvePath=function(){this.curves=[],this.bends=[],this.autoClose=!1},e.CurvePath.prototype=Object.create(e.Curve.prototype),e.CurvePath.prototype.add=function(a){this.curves.push(a)},e.CurvePath.prototype.checkConnection=function(){},e.CurvePath.prototype.closePath=function(){var a=this.curves[0].getPoint(0),b=this.curves[this.curves.length-1].getPoint(1);a.equals(b)||this.curves.push(new e.LineCurve(b,a))},e.CurvePath.prototype.getPoint=function(a){for(var b,c,d=a*this.getLength(),e=this.getCurveLengths(),f=0;f=d){b=e[f]-d,c=this.curves[f];var g=1-b/c.getLength();return c.getPointAt(g)}f++}return null},e.CurvePath.prototype.getLength=function(){var a=this.getCurveLengths();return a[a.length-1]},e.CurvePath.prototype.getCurveLengths=function(){if(this.cacheLengths&&this.cacheLengths.length==this.curves.length)return this.cacheLengths;var a,b=[],c=0,d=this.curves.length;for(a=0;d>a;a++)c+=this.curves[a].getLength(),b.push(c);return this.cacheLengths=b,b},e.CurvePath.prototype.getBoundingBox=function(){var a,b,c,d,f,g,h=this.getPoints();a=b=Number.NEGATIVE_INFINITY,d=f=Number.POSITIVE_INFINITY;var i,j,k,l,m=h[0]instanceof e.Vector3;for(l=m?new e.Vector3:new e.Vector2,j=0,k=h.length;k>j;j++)i=h[j],i.x>a?a=i.x:i.xb?b=i.y:i.yc?c=i.z:i.zc;c++)e=this.getWrapPoints(e,b[c]);return e},e.CurvePath.prototype.getTransformedSpacedPoints=function(a,b){var c,d,e=this.getSpacedPoints(a);for(b||(b=this.bends),c=0,d=b.length;d>c;c++)e=this.getWrapPoints(e,b[c]);return e},e.CurvePath.prototype.getWrapPoints=function(a,b){var c,d,e,f,g,h,i=this.getBoundingBox();for(c=0,d=a.length;d>c;c++){e=a[c],f=e.x,g=e.y,h=f/i.maxX,h=b.getUtoTmapping(h,f);var j=b.getPoint(h),k=b.getTangent(h);k.set(-k.y,k.x).multiplyScalar(g),e.x=j.x+k.x,e.y=j.y+k.y}return a},e.Gyroscope=function(){e.Object3D.call(this)},e.Gyroscope.prototype=Object.create(e.Object3D.prototype),e.Gyroscope.prototype.updateMatrixWorld=function(a){this.matrixAutoUpdate&&this.updateMatrix(),(this.matrixWorldNeedsUpdate||a)&&(this.parent?(this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix),this.matrixWorld.decompose(this.translationWorld,this.quaternionWorld,this.scaleWorld),this.matrix.decompose(this.translationObject,this.quaternionObject,this.scaleObject),this.matrixWorld.compose(this.translationWorld,this.quaternionObject,this.scaleWorld)):this.matrixWorld.copy(this.matrix),this.matrixWorldNeedsUpdate=!1,a=!0);for(var b=0,c=this.children.length;c>b;b++)this.children[b].updateMatrixWorld(a)},e.Gyroscope.prototype.translationWorld=new e.Vector3,e.Gyroscope.prototype.translationObject=new e.Vector3,e.Gyroscope.prototype.quaternionWorld=new e.Quaternion,e.Gyroscope.prototype.quaternionObject=new e.Quaternion,e.Gyroscope.prototype.scaleWorld=new e.Vector3,e.Gyroscope.prototype.scaleObject=new e.Vector3,e.Path=function(a){e.CurvePath.call(this),this.actions=[],a&&this.fromPoints(a)},e.Path.prototype=Object.create(e.CurvePath.prototype),e.PathActions={MOVE_TO:"moveTo",LINE_TO:"lineTo",QUADRATIC_CURVE_TO:"quadraticCurveTo",BEZIER_CURVE_TO:"bezierCurveTo",CSPLINE_THRU:"splineThru",ARC:"arc",ELLIPSE:"ellipse"},e.Path.prototype.fromPoints=function(a){this.moveTo(a[0].x,a[0].y);for(var b=1,c=a.length;c>b;b++)this.lineTo(a[b].x,a[b].y)},e.Path.prototype.moveTo=function(){var a=Array.prototype.slice.call(arguments);this.actions.push({action:e.PathActions.MOVE_TO,args:a})},e.Path.prototype.lineTo=function(a,b){var c=Array.prototype.slice.call(arguments),d=this.actions[this.actions.length-1].args,f=d[d.length-2],g=d[d.length-1],h=new e.LineCurve(new e.Vector2(f,g),new e.Vector2(a,b));this.curves.push(h),this.actions.push({action:e.PathActions.LINE_TO,args:c})},e.Path.prototype.quadraticCurveTo=function(a,b,c,d){var f=Array.prototype.slice.call(arguments),g=this.actions[this.actions.length-1].args,h=g[g.length-2],i=g[g.length-1],j=new e.QuadraticBezierCurve(new e.Vector2(h,i),new e.Vector2(a,b),new e.Vector2(c,d));this.curves.push(j),this.actions.push({action:e.PathActions.QUADRATIC_CURVE_TO,args:f})},e.Path.prototype.bezierCurveTo=function(a,b,c,d,f,g){var h=Array.prototype.slice.call(arguments),i=this.actions[this.actions.length-1].args,j=i[i.length-2],k=i[i.length-1],l=new e.CubicBezierCurve(new e.Vector2(j,k),new e.Vector2(a,b),new e.Vector2(c,d),new e.Vector2(f,g));this.curves.push(l),this.actions.push({action:e.PathActions.BEZIER_CURVE_TO,args:h})},e.Path.prototype.splineThru=function(a){var b=Array.prototype.slice.call(arguments),c=this.actions[this.actions.length-1].args,d=c[c.length-2],f=c[c.length-1],g=[new e.Vector2(d,f)];Array.prototype.push.apply(g,a);var h=new e.SplineCurve(g);this.curves.push(h),this.actions.push({action:e.PathActions.CSPLINE_THRU,args:b})},e.Path.prototype.arc=function(a,b,c,d,e,f){var g=this.actions[this.actions.length-1].args,h=g[g.length-2],i=g[g.length-1];this.absarc(a+h,b+i,c,d,e,f)},e.Path.prototype.absarc=function(a,b,c,d,e,f){this.absellipse(a,b,c,c,d,e,f)},e.Path.prototype.ellipse=function(a,b,c,d,e,f,g){var h=this.actions[this.actions.length-1].args,i=h[h.length-2],j=h[h.length-1];this.absellipse(a+i,b+j,c,d,e,f,g)},e.Path.prototype.absellipse=function(a,b,c,d,f,g,h){var i=Array.prototype.slice.call(arguments),j=new e.EllipseCurve(a,b,c,d,f,g,h);this.curves.push(j);var k=j.getPoint(1);i.push(k.x),i.push(k.y),this.actions.push({action:e.PathActions.ELLIPSE,args:i})},e.Path.prototype.getSpacedPoints=function(a){a||(a=40);for(var b=[],c=0;a>c;c++)b.push(this.getPoint(c/a));return b},e.Path.prototype.getPoints=function(a,b){if(this.useSpacedPoints)return console.log("tata"),this.getSpacedPoints(a,b);a=a||12;var c,d,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v=[];for(c=0,d=this.actions.length;d>c;c++)switch(f=this.actions[c],g=f.action,h=f.args,g){case e.PathActions.MOVE_TO:v.push(new e.Vector2(h[0],h[1]));break;case e.PathActions.LINE_TO:v.push(new e.Vector2(h[0],h[1]));break;case e.PathActions.QUADRATIC_CURVE_TO:for(i=h[2],j=h[3],m=h[0],n=h[1],v.length>0?(q=v[v.length-1],o=q.x,p=q.y):(q=this.actions[c-1].args,o=q[q.length-2],p=q[q.length-1]),r=1;a>=r;r++)s=r/a,t=e.Shape.Utils.b2(s,o,m,i),u=e.Shape.Utils.b2(s,p,n,j),v.push(new e.Vector2(t,u));break;case e.PathActions.BEZIER_CURVE_TO:for(i=h[4],j=h[5],m=h[0],n=h[1],k=h[2],l=h[3],v.length>0?(q=v[v.length-1],o=q.x,p=q.y):(q=this.actions[c-1].args,o=q[q.length-2],p=q[q.length-1]),r=1;a>=r;r++)s=r/a,t=e.Shape.Utils.b3(s,o,m,k,i),u=e.Shape.Utils.b3(s,p,n,l,j),v.push(new e.Vector2(t,u));break;case e.PathActions.CSPLINE_THRU:q=this.actions[c-1].args;var w=new e.Vector2(q[q.length-2],q[q.length-1]),x=[w],y=a*h[0].length;x=x.concat(h[0]);var z=new e.SplineCurve(x);for(r=1;y>=r;r++)v.push(z.getPointAt(r/y));break;case e.PathActions.ARC:var A,B=h[0],C=h[1],D=h[2],E=h[3],F=h[4],G=!!h[5],H=F-E,I=2*a;for(r=1;I>=r;r++)s=r/I,G||(s=1-s),A=E+s*H,t=B+D*Math.cos(A),u=C+D*Math.sin(A),v.push(new e.Vector2(t,u));break;case e.PathActions.ELLIPSE:var A,B=h[0],C=h[1],J=h[2],K=h[3],E=h[4],F=h[5],G=!!h[6],H=F-E,I=2*a;for(r=1;I>=r;r++)s=r/I,G||(s=1-s),A=E+s*H,t=B+J*Math.cos(A),u=C+K*Math.sin(A),v.push(new e.Vector2(t,u))}var L=v[v.length-1],M=1e-10;return Math.abs(L.x-v[0].x)g;f=g++){var h=b[f],i=b[g],j=i.x-h.x,k=i.y-h.y;if(Math.abs(k)>c){if(0>k&&(h=b[g],j=-j,i=b[f],k=-k),a.yi.y)continue;if(a.y==h.y){if(a.x==h.x)return!0}else{var l=k*(a.x-h.x)-j*(a.y-h.y);if(0==l)return!0;if(0>l)continue;e=!e}}else{if(a.y!=h.y)continue;if(i.x<=a.x&&a.x<=h.x||h.x<=a.x&&a.x<=i.x)return!0}}return e}var c,d,f,g,h,i=[],j=new e.Path;for(c=0,d=this.actions.length;d>c;c++)f=this.actions[c],h=f.args,g=f.action,g==e.PathActions.MOVE_TO&&0!=j.actions.length&&(i.push(j),j=new e.Path),j[g].apply(j,h);if(0!=j.actions.length&&i.push(j),0==i.length)return[];var k,l,m,n=[];if(1==i.length)return l=i[0],m=new e.Shape,m.actions=l.actions,m.curves=l.curves,n.push(m),n;var o=!e.Shape.Utils.isClockWise(i[0].getPoints());o=a?!o:o;var p,q=[],r=[],s=[],t=0;for(r[t]=void 0,s[t]=[],c=0,d=i.length;d>c;c++)l=i[c],p=l.getPoints(),k=e.Shape.Utils.isClockWise(p),k=a?!k:k,k?(!o&&r[t]&&t++,r[t]={s:new e.Shape,p:p},r[t].s.actions=l.actions,r[t].s.curves=l.curves,o&&t++,s[t]=[]):s[t].push({h:l,p:p[0]});if(r.length>1){for(var u=!1,v=[],w=0,x=r.length;x>w;w++)q[w]=[];for(var w=0,x=r.length;x>w;w++)for(var y=(r[w],s[w]),z=0;z0&&(u||(s=q))}var D,E,F;for(c=0,d=r.length;d>c;c++)for(m=r[c].s,n.push(m),D=s[c],E=0,F=D.length;F>E;E++)m.holes.push(D[E].h);return n},e.Shape=function(){e.Path.apply(this,arguments),this.holes=[]},e.Shape.prototype=Object.create(e.Path.prototype),e.Shape.prototype.extrude=function(a){var b=new e.ExtrudeGeometry(this,a);return b},e.Shape.prototype.makeGeometry=function(a){var b=new e.ShapeGeometry(this,a);return b},e.Shape.prototype.getPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;c>b;b++)d[b]=this.holes[b].getTransformedPoints(a,this.bends);return d},e.Shape.prototype.getSpacedPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;c>b;b++)d[b]=this.holes[b].getTransformedSpacedPoints(a,this.bends);return d},e.Shape.prototype.extractAllPoints=function(a){return{shape:this.getTransformedPoints(a),holes:this.getPointsHoles(a)}},e.Shape.prototype.extractPoints=function(a){return this.useSpacedPoints?this.extractAllSpacedPoints(a):this.extractAllPoints(a)},e.Shape.prototype.extractAllSpacedPoints=function(a){return{shape:this.getTransformedSpacedPoints(a),holes:this.getSpacedPointsHoles(a)}},e.Shape.Utils={triangulateShape:function(a,b){function c(a,b,c){return a.x!=b.x?a.xg){var p;if(n>0){if(0>o||o>n)return[];if(p=k*l-j*m,0>p||p>n)return[]}else{if(o>0||n>o)return[];if(p=k*l-j*m,p>0||n>p)return[]}if(0==p)return!f||0!=o&&o!=n?[a]:[];if(p==n)return!f||0!=o&&o!=n?[b]:[];if(0==o)return[d];if(o==n)return[e];var q=p/n;return[{x:a.x+q*h,y:a.y+q*i}]}if(0!=o||k*l!=j*m)return[];var r=0==h&&0==i,s=0==j&&0==k;if(r&&s)return a.x!=d.x||a.y!=d.y?[]:[a];if(r)return c(d,e,a)?[a]:[];if(s)return c(a,b,d)?[d]:[];var t,u,v,w,x,y,z,A;return 0!=h?(a.x=v?z>w?[]:w==z?f?[]:[x]:A>=w?[x,u]:[x,y]:v>A?[]:v==A?f?[]:[t]:A>=w?[t,u]:[t,y]}function f(a,b,c,d){var e=1e-10,f=b.x-a.x,g=b.y-a.y,h=c.x-a.x,i=c.y-a.y,j=d.x-a.x,k=d.y-a.y,l=f*i-g*h,m=f*k-g*j;if(Math.abs(l)>e){var n=j*i-k*h;return l>0?m>=0&&n>=0:m>=0||n>=0}return m>0}function g(a,b){function c(a,b){var c=s.length-1,d=a-1;0>d&&(d=c);var e=a+1;e>c&&(e=0);var g=f(s[a],s[d],s[e],h[b]);if(!g)return!1;var i=h.length-1,j=b-1;0>j&&(j=i);var k=b+1;return k>i&&(k=0),g=f(h[b],h[j],h[k],s[a]),g?!0:!1}function e(a,b){var c,e,f;for(c=0;c0)return!0;return!1}function g(a,c){var e,f,g,h,i;for(e=0;e0)return!0;return!1}for(var h,i,j,k,l,m,n,o,p,q,r,s=a.concat(),t=[],u=[],v=0,w=b.length;w>v;v++)t.push(v);for(var x=2*t.length;t.length>0;){if(x--,0>x){console.log("Infinite Loop! Holes left:"+t.length+", Probably Hole outside Shape!");break}for(j=0;j=0)break;u[n]=!0}if(i>=0)break}}return s}for(var h,i,j,k,l,m,n={},o=a.concat(),p=0,q=b.length;q>p;p++)Array.prototype.push.apply(o,b[p]);for(h=0,i=o.length;i>h;h++)l=o[h].x+":"+o[h].y,void 0!==n[l]&&console.log("Duplicate point",l),n[l]=h;var r=g(a,b),s=e.FontUtils.Triangulate(r,!1);for(h=0,i=s.length;i>h;h++)for(k=s[h],j=0;3>j;j++)l=k[j].x+":"+k[j].y,m=n[l],void 0!==m&&(k[j]=m);return s.concat()},isClockWise:function(a){return e.FontUtils.Triangulate.area(a)<0},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){var c=1-a;return 3*c*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a,b)+this.b3p1(a,c)+this.b3p2(a,d)+this.b3p3(a,e)}},e.LineCurve=function(a,b){this.v1=a,this.v2=b},e.LineCurve.prototype=Object.create(e.Curve.prototype),e.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);return b.multiplyScalar(a).add(this.v1),b},e.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)},e.LineCurve.prototype.getTangent=function(){var a=this.v2.clone().sub(this.v1);return a.normalize()},e.QuadraticBezierCurve=function(a,b,c){this.v0=a,this.v1=b,this.v2=c},e.QuadraticBezierCurve.prototype=Object.create(e.Curve.prototype),e.QuadraticBezierCurve.prototype.getPoint=function(a){var b,c;return b=e.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x),c=e.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y),new e.Vector2(b,c)},e.QuadraticBezierCurve.prototype.getTangent=function(a){var b,c;b=e.Curve.Utils.tangentQuadraticBezier(a,this.v0.x,this.v1.x,this.v2.x),c=e.Curve.Utils.tangentQuadraticBezier(a,this.v0.y,this.v1.y,this.v2.y);var d=new e.Vector2(b,c);return d.normalize(),d},e.CubicBezierCurve=function(a,b,c,d){this.v0=a,this.v1=b,this.v2=c,this.v3=d},e.CubicBezierCurve.prototype=Object.create(e.Curve.prototype),e.CubicBezierCurve.prototype.getPoint=function(a){var b,c;return b=e.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),c=e.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y),new e.Vector2(b,c)},e.CubicBezierCurve.prototype.getTangent=function(a){var b,c;b=e.Curve.Utils.tangentCubicBezier(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),c=e.Curve.Utils.tangentCubicBezier(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);var d=new e.Vector2(b,c);return d.normalize(),d},e.SplineCurve=function(a){this.points=void 0==a?[]:a},e.SplineCurve.prototype=Object.create(e.Curve.prototype),e.SplineCurve.prototype.getPoint=function(a){var b,c,d,f=new e.Vector2,g=[],h=this.points;return b=(h.length-1)*a,c=Math.floor(b),d=b-c,g[0]=0==c?c:c-1,g[1]=c,g[2]=c>h.length-2?h.length-1:c+1,g[3]=c>h.length-3?h.length-1:c+2,f.x=e.Curve.Utils.interpolate(h[g[0]].x,h[g[1]].x,h[g[2]].x,h[g[3]].x,d),f.y=e.Curve.Utils.interpolate(h[g[0]].y,h[g[1]].y,h[g[2]].y,h[g[3]].y,d),f},e.EllipseCurve=function(a,b,c,d,e,f,g){this.aX=a,this.aY=b,this.xRadius=c,this.yRadius=d,this.aStartAngle=e,this.aEndAngle=f,this.aClockwise=g},e.EllipseCurve.prototype=Object.create(e.Curve.prototype),e.EllipseCurve.prototype.getPoint=function(a){var b,c=this.aEndAngle-this.aStartAngle;0>c&&(c+=2*Math.PI),c>2*Math.PI&&(c-=2*Math.PI),b=this.aClockwise===!0?this.aEndAngle+(1-a)*(2*Math.PI-c):this.aStartAngle+a*c; -var d=this.aX+this.xRadius*Math.cos(b),f=this.aY+this.yRadius*Math.sin(b);return new e.Vector2(d,f)},e.ArcCurve=function(a,b,c,d,f,g){e.EllipseCurve.call(this,a,b,c,c,d,f,g)},e.ArcCurve.prototype=Object.create(e.EllipseCurve.prototype),e.LineCurve3=e.Curve.create(function(a,b){this.v1=a,this.v2=b},function(a){var b=new e.Vector3;return b.subVectors(this.v2,this.v1),b.multiplyScalar(a),b.add(this.v1),b}),e.QuadraticBezierCurve3=e.Curve.create(function(a,b,c){this.v0=a,this.v1=b,this.v2=c},function(a){var b,c,d;return b=e.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x),c=e.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y),d=e.Shape.Utils.b2(a,this.v0.z,this.v1.z,this.v2.z),new e.Vector3(b,c,d)}),e.CubicBezierCurve3=e.Curve.create(function(a,b,c,d){this.v0=a,this.v1=b,this.v2=c,this.v3=d},function(a){var b,c,d;return b=e.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),c=e.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y),d=e.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z),new e.Vector3(b,c,d)}),e.SplineCurve3=e.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b,c,d,f=new e.Vector3,g=[],h=this.points;b=(h.length-1)*a,c=Math.floor(b),d=b-c,g[0]=0==c?c:c-1,g[1]=c,g[2]=c>h.length-2?h.length-1:c+1,g[3]=c>h.length-3?h.length-1:c+2;var i=h[g[0]],j=h[g[1]],k=h[g[2]],l=h[g[3]];return f.x=e.Curve.Utils.interpolate(i.x,j.x,k.x,l.x,d),f.y=e.Curve.Utils.interpolate(i.y,j.y,k.y,l.y,d),f.z=e.Curve.Utils.interpolate(i.z,j.z,k.z,l.z,d),f}),e.ClosedSplineCurve3=e.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b,c,d,f=new e.Vector3,g=[],h=this.points;return b=(h.length-0)*a,c=Math.floor(b),d=b-c,c+=c>0?0:(Math.floor(Math.abs(c)/h.length)+1)*h.length,g[0]=(c-1)%h.length,g[1]=c%h.length,g[2]=(c+1)%h.length,g[3]=(c+2)%h.length,f.x=e.Curve.Utils.interpolate(h[g[0]].x,h[g[1]].x,h[g[2]].x,h[g[3]].x,d),f.y=e.Curve.Utils.interpolate(h[g[0]].y,h[g[1]].y,h[g[2]].y,h[g[3]].y,d),f.z=e.Curve.Utils.interpolate(h[g[0]].z,h[g[1]].z,h[g[2]].z,h[g[3]].z,d),f}),e.AnimationHandler=function(){var a=[],b={},c={};c.update=function(b){for(var c=0;ca;a++){var c=this.hierarchy[a];c.matrixAutoUpdate=!0,void 0===c.animationCache&&(c.animationCache={},c.animationCache.prevKey={pos:0,rot:0,scl:0},c.animationCache.nextKey={pos:0,rot:0,scl:0},c.animationCache.originalMatrix=c instanceof e.Bone?c.skinMatrix:c.matrix);var d=c.animationCache.prevKey,f=c.animationCache.nextKey;d.pos=this.data.hierarchy[a].keys[0],d.rot=this.data.hierarchy[a].keys[0],d.scl=this.data.hierarchy[a].keys[0],f.pos=this.getNextKeyWith("pos",a,1),f.rot=this.getNextKeyWith("rot",a,1),f.scl=this.getNextKeyWith("scl",a,1)}},e.Animation.prototype.update=function(){var a=[],b=new e.Vector3,c=function(a,b){var c,e,f,g,h,i,j,k,l,m=[],n=[];return c=(a.length-1)*b,e=Math.floor(c),f=c-e,m[0]=0===e?e:e-1,m[1]=e,m[2]=e>a.length-2?e:e+1,m[3]=e>a.length-3?e:e+2,i=a[m[0]],j=a[m[1]],k=a[m[2]],l=a[m[3]],g=f*f,h=f*g,n[0]=d(i[0],j[0],k[0],l[0],f,g,h),n[1]=d(i[1],j[1],k[1],l[1],f,g,h),n[2]=d(i[2],j[2],k[2],l[2],f,g,h),n},d=function(a,b,c,d,e,f,g){var h=.5*(c-a),i=.5*(d-b);return(2*(b-c)+h+i)*g+(-3*(b-c)-2*h-i)*f+h*e+b};return function(d){if(this.isPlaying!==!1){this.currentTime+=d*this.timeScale;var f,g=["pos","rot","scl"],h=this.data.length;if(this.loop===!0&&this.currentTime>h)this.currentTime%=h,this.reset();else if(this.loop===!1&&this.currentTime>h)return void this.stop();this.currentTime=Math.min(this.currentTime,h);for(var i=0,j=this.hierarchy.length;j>i;i++)for(var k=this.hierarchy[i],l=k.animationCache,m=0;3>m;m++){var n=g[m],o=l.prevKey[n],p=l.nextKey[n];if(p.time<=this.currentTime){for(o=this.data.hierarchy[i].keys[0],p=this.getNextKeyWith(n,i,1);p.timeo.index;)o=p,p=this.getNextKeyWith(n,i,p.index+1);l.prevKey[n]=o,l.nextKey[n]=p}k.matrixAutoUpdate=!0,k.matrixWorldNeedsUpdate=!0;var q=(this.currentTime-o.time)/(p.time-o.time),r=o[n],s=p[n];if(0>q&&(q=0),q>1&&(q=1),"pos"===n){if(f=k.position,this.interpolationType===e.AnimationHandler.LINEAR)f.x=r[0]+(s[0]-r[0])*q,f.y=r[1]+(s[1]-r[1])*q,f.z=r[2]+(s[2]-r[2])*q;else if(this.interpolationType===e.AnimationHandler.CATMULLROM||this.interpolationType===e.AnimationHandler.CATMULLROM_FORWARD){a[0]=this.getPrevKeyWith("pos",i,o.index-1).pos,a[1]=r,a[2]=s,a[3]=this.getNextKeyWith("pos",i,p.index+1).pos,q=.33*q+.33;var t=c(a,q);if(f.x=t[0],f.y=t[1],f.z=t[2],this.interpolationType===e.AnimationHandler.CATMULLROM_FORWARD){var u=c(a,1.01*q);b.set(u[0],u[1],u[2]),b.sub(f),b.y=0,b.normalize();var v=Math.atan2(b.x,b.z);k.rotation.set(0,v,0)}}}else"rot"===n?e.Quaternion.slerp(r,s,k.quaternion,q):"scl"===n&&(f=k.scale,f.x=r[0]+(s[0]-r[0])*q,f.y=r[1]+(s[1]-r[1])*q,f.z=r[2]+(s[2]-r[2])*q)}}}}(),e.Animation.prototype.getNextKeyWith=function(a,b,c){var d=this.data.hierarchy[b].keys;for(this.interpolationType===e.AnimationHandler.CATMULLROM||this.interpolationType===e.AnimationHandler.CATMULLROM_FORWARD?c=c0?c:0:c>=0?c:c+d.length;c>=0;c--)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[d.length-1]},e.KeyFrameAnimation=function(a,b){this.root=a,this.data=e.AnimationHandler.get(b),this.hierarchy=e.AnimationHandler.parse(a),this.currentTime=0,this.timeScale=.001,this.isPlaying=!1,this.isPaused=!0,this.loop=!0;for(var c=0,d=this.hierarchy.length;d>c;c++){var f=this.data.hierarchy[c].keys,g=this.data.hierarchy[c].sids,h=this.hierarchy[c];if(f.length&&g){for(var i=0;ib;b++){c=this.hierarchy[b],d=this.data.hierarchy[b],void 0===d.animationCache&&(d.animationCache={},d.animationCache.prevKey=null,d.animationCache.nextKey=null,d.animationCache.originalMatrix=c instanceof e.Bone?c.skinMatrix:c.matrix);var g=this.data.hierarchy[b].keys;g.length&&(d.animationCache.prevKey=g[0],d.animationCache.nextKey=g[1],this.startTime=Math.min(g[0].time,this.startTime),this.endTime=Math.max(g[g.length-1].time,this.endTime))}this.update(0)}this.isPaused=!1,e.AnimationHandler.addToUpdate(this)},e.KeyFrameAnimation.prototype.pause=function(){this.isPaused?e.AnimationHandler.addToUpdate(this):e.AnimationHandler.removeFromUpdate(this),this.isPaused=!this.isPaused},e.KeyFrameAnimation.prototype.stop=function(){this.isPlaying=!1,this.isPaused=!1,e.AnimationHandler.removeFromUpdate(this);for(var a=0;ab&&(this.currentTime%=b),this.currentTime=Math.min(this.currentTime,b);for(var c=0,d=this.hierarchy.length;d>c;c++){var e=this.hierarchy[c],f=this.data.hierarchy[c],g=f.keys,h=f.animationCache;if(g.length){var i=h.prevKey,j=h.nextKey;if(j.time<=this.currentTime){for(;j.timei.index;)i=j,j=g[i.index+1];h.prevKey=i,h.nextKey=j}j.time>=this.currentTime?i.interpolate(j,this.currentTime):i.interpolate(j,j.time),this.data.hierarchy[c].node.updateMatrix(),e.matrixWorldNeedsUpdate=!0}}}},e.KeyFrameAnimation.prototype.getNextKeyWith=function(a,b,c){var d=this.data.hierarchy[b].keys;for(c%=d.length;c=0?c:c+d.length;c>=0;c--)if(d[c].hasTarget(a))return d[c];return d[d.length-1]},e.MorphAnimation=function(a){this.mesh=a,this.frames=a.morphTargetInfluences.length,this.currentTime=0,this.duration=1e3,this.loop=!0,this.isPlaying=!1},e.MorphAnimation.prototype={play:function(){this.isPlaying=!0},pause:function(){this.isPlaying=!1},update:function(){var a=0,b=0;return function(c){if(this.isPlaying!==!1){this.currentTime+=c,this.loop===!0&&this.currentTime>this.duration&&(this.currentTime%=this.duration),this.currentTime=Math.min(this.currentTime,this.duration);var d=this.duration/this.frames,e=Math.floor(this.currentTime/d);e!=b&&(this.mesh.morphTargetInfluences[a]=0,this.mesh.morphTargetInfluences[b]=1,this.mesh.morphTargetInfluences[e]=0,a=b,b=e),this.mesh.morphTargetInfluences[e]=this.currentTime%d/d,this.mesh.morphTargetInfluences[a]=1-this.mesh.morphTargetInfluences[e]}}}()},e.CubeCamera=function(a,b,c){e.Object3D.call(this);var d=90,f=1,g=new e.PerspectiveCamera(d,f,a,b);g.up.set(0,-1,0),g.lookAt(new e.Vector3(1,0,0)),this.add(g);var h=new e.PerspectiveCamera(d,f,a,b);h.up.set(0,-1,0),h.lookAt(new e.Vector3(-1,0,0)),this.add(h);var i=new e.PerspectiveCamera(d,f,a,b);i.up.set(0,0,1),i.lookAt(new e.Vector3(0,1,0)),this.add(i);var j=new e.PerspectiveCamera(d,f,a,b);j.up.set(0,0,-1),j.lookAt(new e.Vector3(0,-1,0)),this.add(j);var k=new e.PerspectiveCamera(d,f,a,b);k.up.set(0,-1,0),k.lookAt(new e.Vector3(0,0,1)),this.add(k);var l=new e.PerspectiveCamera(d,f,a,b);l.up.set(0,-1,0),l.lookAt(new e.Vector3(0,0,-1)),this.add(l),this.renderTarget=new e.WebGLRenderTargetCube(c,c,{format:e.RGBFormat,magFilter:e.LinearFilter,minFilter:e.LinearFilter}),this.updateCubeMap=function(a,b){var c=this.renderTarget,d=c.generateMipmaps;c.generateMipmaps=!1,c.activeCubeFace=0,a.render(b,g,c),c.activeCubeFace=1,a.render(b,h,c),c.activeCubeFace=2,a.render(b,i,c),c.activeCubeFace=3,a.render(b,j,c),c.activeCubeFace=4,a.render(b,k,c),c.generateMipmaps=d,c.activeCubeFace=5,a.render(b,l,c)}},e.CubeCamera.prototype=Object.create(e.Object3D.prototype),e.CombinedCamera=function(a,b,c,d,f,g,h){e.Camera.call(this),this.fov=c,this.left=-a/2,this.right=a/2,this.top=b/2,this.bottom=-b/2,this.cameraO=new e.OrthographicCamera(a/-2,a/2,b/2,b/-2,g,h),this.cameraP=new e.PerspectiveCamera(c,a/b,d,f),this.zoom=1,this.toPerspective()},e.CombinedCamera.prototype=Object.create(e.Camera.prototype),e.CombinedCamera.prototype.toPerspective=function(){this.near=this.cameraP.near,this.far=this.cameraP.far,this.cameraP.fov=this.fov/this.zoom,this.cameraP.updateProjectionMatrix(),this.projectionMatrix=this.cameraP.projectionMatrix,this.inPerspectiveMode=!0,this.inOrthographicMode=!1},e.CombinedCamera.prototype.toOrthographic=function(){var a=this.fov,b=this.cameraP.aspect,c=this.cameraP.near,d=this.cameraP.far,e=(c+d)/2,f=Math.tan(a/2)*e,g=2*f,h=g*b,i=h/2;f/=this.zoom,i/=this.zoom,this.cameraO.left=-i,this.cameraO.right=i,this.cameraO.top=f,this.cameraO.bottom=-f,this.cameraO.updateProjectionMatrix(),this.near=this.cameraO.near,this.far=this.cameraO.far,this.projectionMatrix=this.cameraO.projectionMatrix,this.inPerspectiveMode=!1,this.inOrthographicMode=!0},e.CombinedCamera.prototype.setSize=function(a,b){this.cameraP.aspect=a/b,this.left=-a/2,this.right=a/2,this.top=b/2,this.bottom=-b/2},e.CombinedCamera.prototype.setFov=function(a){this.fov=a,this.inPerspectiveMode?this.toPerspective():this.toOrthographic()},e.CombinedCamera.prototype.updateProjectionMatrix=function(){this.inPerspectiveMode?this.toPerspective():(this.toPerspective(),this.toOrthographic())},e.CombinedCamera.prototype.setLens=function(a,b){void 0===b&&(b=24);var c=2*e.Math.radToDeg(Math.atan(b/(2*a)));return this.setFov(c),c},e.CombinedCamera.prototype.setZoom=function(a){this.zoom=a,this.inPerspectiveMode?this.toPerspective():this.toOrthographic()},e.CombinedCamera.prototype.toFrontView=function(){this.rotation.x=0,this.rotation.y=0,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toBackView=function(){this.rotation.x=0,this.rotation.y=Math.PI,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toLeftView=function(){this.rotation.x=0,this.rotation.y=-Math.PI/2,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toRightView=function(){this.rotation.x=0,this.rotation.y=Math.PI/2,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toTopView=function(){this.rotation.x=-Math.PI/2,this.rotation.y=0,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toBottomView=function(){this.rotation.x=Math.PI/2,this.rotation.y=0,this.rotation.z=0,this.rotationAutoUpdate=!1},e.BoxGeometry=function(a,b,c,d,f,g){function h(a,b,c,d,f,g,h,j){var k,l,m,n=i.widthSegments,o=i.heightSegments,p=f/2,q=g/2,r=i.vertices.length;"x"===a&&"y"===b||"y"===a&&"x"===b?k="z":"x"===a&&"z"===b||"z"===a&&"x"===b?(k="y",o=i.depthSegments):("z"===a&&"y"===b||"y"===a&&"z"===b)&&(k="x",n=i.depthSegments);var s=n+1,t=o+1,u=f/n,v=g/o,w=new e.Vector3;for(w[k]=h>0?1:-1,m=0;t>m;m++)for(l=0;s>l;l++){var x=new e.Vector3;x[a]=(l*u-p)*c,x[b]=(m*v-q)*d,x[k]=h,i.vertices.push(x)}for(m=0;o>m;m++)for(l=0;n>l;l++){var y=l+s*m,z=l+s*(m+1),A=l+1+s*(m+1),B=l+1+s*m,C=new e.Vector2(l/n,1-m/o),D=new e.Vector2(l/n,1-(m+1)/o),E=new e.Vector2((l+1)/n,1-(m+1)/o),F=new e.Vector2((l+1)/n,1-m/o),G=new e.Face3(y+r,z+r,B+r);G.normal.copy(w),G.vertexNormals.push(w.clone(),w.clone(),w.clone()),G.materialIndex=j,i.faces.push(G),i.faceVertexUvs[0].push([C,D,F]),G=new e.Face3(z+r,A+r,B+r),G.normal.copy(w),G.vertexNormals.push(w.clone(),w.clone(),w.clone()),G.materialIndex=j,i.faces.push(G),i.faceVertexUvs[0].push([D.clone(),E,F.clone()])}}e.Geometry.call(this);var i=this;this.width=a,this.height=b,this.depth=c,this.widthSegments=d||1,this.heightSegments=f||1,this.depthSegments=g||1;var j=this.width/2,k=this.height/2,l=this.depth/2;h("z","y",-1,-1,this.depth,this.height,j,0),h("z","y",1,-1,this.depth,this.height,-j,1),h("x","z",1,1,this.width,this.depth,k,2),h("x","z",1,-1,this.width,this.depth,-k,3),h("x","y",1,-1,this.width,this.height,l,4),h("x","y",-1,-1,this.width,this.height,-l,5),this.computeCentroids(),this.mergeVertices()},e.BoxGeometry.prototype=Object.create(e.Geometry.prototype),e.CircleGeometry=function(a,b,c,d){e.Geometry.call(this),this.radius=a=a||50,this.segments=b=void 0!==b?Math.max(3,b):8,this.thetaStart=c=void 0!==c?c:0,this.thetaLength=d=void 0!==d?d:2*Math.PI;var f,g=[],h=new e.Vector3,i=new e.Vector2(.5,.5);for(this.vertices.push(h),g.push(i),f=0;b>=f;f++){var j=new e.Vector3,k=c+f/b*d;j.x=a*Math.cos(k),j.y=a*Math.sin(k),this.vertices.push(j),g.push(new e.Vector2((j.x/a+1)/2,(j.y/a+1)/2))}var l=new e.Vector3(0,0,1);for(f=1;b>=f;f++){var m=f,n=f+1,o=0;this.faces.push(new e.Face3(m,n,o,[l.clone(),l.clone(),l.clone()])),this.faceVertexUvs[0].push([g[f].clone(),g[f+1].clone(),i.clone()])}this.computeCentroids(),this.computeFaceNormals(),this.boundingSphere=new e.Sphere(new e.Vector3,a)},e.CircleGeometry.prototype=Object.create(e.Geometry.prototype),e.CubeGeometry=e.BoxGeometry,e.CylinderGeometry=function(a,b,c,d,f,g){e.Geometry.call(this),this.radiusTop=a=void 0!==a?a:20,this.radiusBottom=b=void 0!==b?b:20,this.height=c=void 0!==c?c:100,this.radialSegments=d=d||8,this.heightSegments=f=f||1,this.openEnded=g=void 0!==g?g:!1;var h,i,j=c/2,k=[],l=[];for(i=0;f>=i;i++){var m=[],n=[],o=i/f,p=o*(b-a)+a;for(h=0;d>=h;h++){var q=h/d,r=new e.Vector3;r.x=p*Math.sin(q*Math.PI*2),r.y=-o*c+j,r.z=p*Math.cos(q*Math.PI*2),this.vertices.push(r),m.push(this.vertices.length-1),n.push(new e.Vector2(q,1-o))}k.push(m),l.push(n)}var s,t,u=(b-a)/c;for(h=0;d>h;h++)for(0!==a?(s=this.vertices[k[0][h]].clone(),t=this.vertices[k[0][h+1]].clone()):(s=this.vertices[k[1][h]].clone(),t=this.vertices[k[1][h+1]].clone()),s.setY(Math.sqrt(s.x*s.x+s.z*s.z)*u).normalize(),t.setY(Math.sqrt(t.x*t.x+t.z*t.z)*u).normalize(),i=0;f>i;i++){var v=k[i][h],w=k[i+1][h],x=k[i+1][h+1],y=k[i][h+1],z=s.clone(),A=s.clone(),B=t.clone(),C=t.clone(),D=l[i][h].clone(),E=l[i+1][h].clone(),F=l[i+1][h+1].clone(),G=l[i][h+1].clone();this.faces.push(new e.Face3(v,w,y,[z,A,C])),this.faceVertexUvs[0].push([D,E,G]),this.faces.push(new e.Face3(w,x,y,[A.clone(),B,C.clone()])),this.faceVertexUvs[0].push([E.clone(),F,G.clone()])}if(g===!1&&a>0)for(this.vertices.push(new e.Vector3(0,j,0)),h=0;d>h;h++){var v=k[0][h],w=k[0][h+1],x=this.vertices.length-1,z=new e.Vector3(0,1,0),A=new e.Vector3(0,1,0),B=new e.Vector3(0,1,0),D=l[0][h].clone(),E=l[0][h+1].clone(),F=new e.Vector2(E.x,0);this.faces.push(new e.Face3(v,w,x,[z,A,B])),this.faceVertexUvs[0].push([D,E,F])}if(g===!1&&b>0)for(this.vertices.push(new e.Vector3(0,-j,0)),h=0;d>h;h++){var v=k[i][h+1],w=k[i][h],x=this.vertices.length-1,z=new e.Vector3(0,-1,0),A=new e.Vector3(0,-1,0),B=new e.Vector3(0,-1,0),D=l[i][h+1].clone(),E=l[i][h].clone(),F=new e.Vector2(E.x,1);this.faces.push(new e.Face3(v,w,x,[z,A,B])),this.faceVertexUvs[0].push([D,E,F])}this.computeCentroids(),this.computeFaceNormals()},e.CylinderGeometry.prototype=Object.create(e.Geometry.prototype),e.ExtrudeGeometry=function(a,b){return"undefined"==typeof a?void(a=[]):(e.Geometry.call(this),a=a instanceof Array?a:[a],this.shapebb=a[a.length-1].getBoundingBox(),this.addShapeList(a,b),this.computeCentroids(),void this.computeFaceNormals())},e.ExtrudeGeometry.prototype=Object.create(e.Geometry.prototype),e.ExtrudeGeometry.prototype.addShapeList=function(a,b){for(var c=a.length,d=0;c>d;d++){var e=a[d];this.addShape(e,b)}},e.ExtrudeGeometry.prototype.addShape=function(a,b){function c(a,b,c){return b||console.log("die"),b.clone().multiplyScalar(c).add(a)}function d(a,b,c){var d,f,g=1e-10,h=e.Math.sign,i=1,j=a.x-b.x,k=a.y-b.y,l=c.x-a.x,m=c.y-a.y,n=j*j+k*k,o=j*m-k*l;if(Math.abs(o)>g){var p=Math.sqrt(n),q=Math.sqrt(l*l+m*m),r=b.x-k/p,s=b.y+j/p,t=c.x-m/q,u=c.y+l/q,v=((t-r)*m-(u-s)*l)/(j*m-k*l);d=r+j*v-a.x,f=s+k*v-a.y;var w=d*d+f*f;if(2>=w)return new e.Vector2(d,f);i=Math.sqrt(w/2)}else{var x=!1;j>g?l>g&&(x=!0):-g>j?-g>l&&(x=!0):h(k)==h(m)&&(x=!0),x?(d=-k,f=j,i=Math.sqrt(n)):(d=j,f=k,i=Math.sqrt(n/2))}return new e.Vector2(d/i,f/i)}function f(){if(u){var a=0,b=T*a;for(W=0;U>W;W++)S=L[W],j(S[2]+b,S[1]+b,S[0]+b,!0);for(a=w+2*t,b=T*a,W=0;U>W;W++)S=L[W],j(S[0]+b,S[1]+b,S[2]+b,!1)}else{for(W=0;U>W;W++)S=L[W],j(S[2],S[1],S[0],!0);for(W=0;U>W;W++)S=L[W],j(S[0]+T*w,S[1]+T*w,S[2]+T*w,!1)}}function g(){var a=0;for(h(M,a),a+=M.length,D=0,E=J.length;E>D;D++)C=J[D],h(C,a),a+=C.length}function h(a,b){var c,d;for(W=a.length;--W>=0;){c=W,d=W-1,0>d&&(d=a.length-1);var e=0,f=w+2*t;for(e=0;f>e;e++){var g=T*e,h=T*(e+1),i=b+c+g,j=b+d+g,l=b+d+h,m=b+c+h;k(i,j,l,m,a,e,f,c,d)}}}function i(a,b,c){F.vertices.push(new e.Vector3(a,b,c))}function j(c,d,f,g){c+=G,d+=G,f+=G,F.faces.push(new e.Face3(c,d,f,null,null,z));var h=g?B.generateBottomUV(F,a,b,c,d,f):B.generateTopUV(F,a,b,c,d,f);F.faceVertexUvs[0].push(h)}function k(c,d,f,g,h,i,j,k,l){c+=G,d+=G,f+=G,g+=G,F.faces.push(new e.Face3(c,d,g,null,null,A)),F.faces.push(new e.Face3(d,f,g,null,null,A));var m=B.generateSideWallUV(F,a,h,b,c,d,f,g,i,j,k,l);F.faceVertexUvs[0].push([m[0],m[1],m[3]]),F.faceVertexUvs[0].push([m[1],m[2],m[3]])}{var l,m,n,o,p,q=void 0!==b.amount?b.amount:100,r=void 0!==b.bevelThickness?b.bevelThickness:6,s=void 0!==b.bevelSize?b.bevelSize:r-2,t=void 0!==b.bevelSegments?b.bevelSegments:3,u=void 0!==b.bevelEnabled?b.bevelEnabled:!0,v=void 0!==b.curveSegments?b.curveSegments:12,w=void 0!==b.steps?b.steps:1,x=b.extrudePath,y=!1,z=b.material,A=b.extrudeMaterial,B=void 0!==b.UVGenerator?b.UVGenerator:e.ExtrudeGeometry.WorldUVGenerator;this.shapebb}x&&(l=x.getSpacedPoints(w),y=!0,u=!1,m=void 0!==b.frames?b.frames:new e.TubeGeometry.FrenetFrames(x,w,!1),n=new e.Vector3,o=new e.Vector3,p=new e.Vector3),u||(t=0,r=0,s=0);var C,D,E,F=this,G=this.vertices.length,H=a.extractPoints(v),I=H.shape,J=H.holes,K=!e.Shape.Utils.isClockWise(I);if(K){for(I=I.reverse(),D=0,E=J.length;E>D;D++)C=J[D],e.Shape.Utils.isClockWise(C)&&(J[D]=C.reverse());K=!1}var L=e.Shape.Utils.triangulateShape(I,J),M=I;for(D=0,E=J.length;E>D;D++)C=J[D],I=I.concat(C);for(var N,O,P,Q,R,S,T=I.length,U=L.length,V=(M.length,180/Math.PI,[]),W=0,X=M.length,Y=X-1,Z=W+1;X>W;W++,Y++,Z++){Y===X&&(Y=0),Z===X&&(Z=0);{M[W],M[Y],M[Z]}V[W]=d(M[W],M[Y],M[Z])}var $,_=[],ab=V.concat();for(D=0,E=J.length;E>D;D++){for(C=J[D],$=[],W=0,X=C.length,Y=X-1,Z=W+1;X>W;W++,Y++,Z++)Y===X&&(Y=0),Z===X&&(Z=0),$[W]=d(C[W],C[Y],C[Z]);_.push($),ab=ab.concat($)}for(N=0;t>N;N++){for(P=N/t,Q=r*(1-P),O=s*Math.sin(P*Math.PI/2),W=0,X=M.length;X>W;W++)R=c(M[W],V[W],O),i(R.x,R.y,-Q);for(D=0,E=J.length;E>D;D++)for(C=J[D],$=_[D],W=0,X=C.length;X>W;W++)R=c(C[W],$[W],O),i(R.x,R.y,-Q)}for(O=s,W=0;T>W;W++)R=u?c(I[W],ab[W],O):I[W],y?(o.copy(m.normals[0]).multiplyScalar(R.x),n.copy(m.binormals[0]).multiplyScalar(R.y),p.copy(l[0]).add(o).add(n),i(p.x,p.y,p.z)):i(R.x,R.y,0);var bb;for(bb=1;w>=bb;bb++)for(W=0;T>W;W++)R=u?c(I[W],ab[W],O):I[W],y?(o.copy(m.normals[bb]).multiplyScalar(R.x),n.copy(m.binormals[bb]).multiplyScalar(R.y),p.copy(l[bb]).add(o).add(n),i(p.x,p.y,p.z)):i(R.x,R.y,q/w*bb);for(N=t-1;N>=0;N--){for(P=N/t,Q=r*(1-P),O=s*Math.sin(P*Math.PI/2),W=0,X=M.length;X>W;W++)R=c(M[W],V[W],O),i(R.x,R.y,q+Q);for(D=0,E=J.length;E>D;D++)for(C=J[D],$=_[D],W=0,X=C.length;X>W;W++)R=c(C[W],$[W],O),y?i(R.x,R.y+l[w-1].y,l[w-1].x+Q):i(R.x,R.y,q+Q)}f(),g()},e.ExtrudeGeometry.WorldUVGenerator={generateTopUV:function(a,b,c,d,f,g){var h=a.vertices[d].x,i=a.vertices[d].y,j=a.vertices[f].x,k=a.vertices[f].y,l=a.vertices[g].x,m=a.vertices[g].y;return[new e.Vector2(h,i),new e.Vector2(j,k),new e.Vector2(l,m)]},generateBottomUV:function(a,b,c,d,e,f){return this.generateTopUV(a,b,c,d,e,f)},generateSideWallUV:function(a,b,c,d,f,g,h,i){var j=a.vertices[f].x,k=a.vertices[f].y,l=a.vertices[f].z,m=a.vertices[g].x,n=a.vertices[g].y,o=a.vertices[g].z,p=a.vertices[h].x,q=a.vertices[h].y,r=a.vertices[h].z,s=a.vertices[i].x,t=a.vertices[i].y,u=a.vertices[i].z;return Math.abs(k-n)<.01?[new e.Vector2(j,1-l),new e.Vector2(m,1-o),new e.Vector2(p,1-r),new e.Vector2(s,1-u)]:[new e.Vector2(k,1-l),new e.Vector2(n,1-o),new e.Vector2(q,1-r),new e.Vector2(t,1-u)]}},e.ExtrudeGeometry.__v1=new e.Vector2,e.ExtrudeGeometry.__v2=new e.Vector2,e.ExtrudeGeometry.__v3=new e.Vector2,e.ExtrudeGeometry.__v4=new e.Vector2,e.ExtrudeGeometry.__v5=new e.Vector2,e.ExtrudeGeometry.__v6=new e.Vector2,e.ShapeGeometry=function(a,b){e.Geometry.call(this),a instanceof Array==!1&&(a=[a]),this.shapebb=a[a.length-1].getBoundingBox(),this.addShapeList(a,b),this.computeCentroids(),this.computeFaceNormals()},e.ShapeGeometry.prototype=Object.create(e.Geometry.prototype),e.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;d>c;c++)this.addShape(a[c],b);return this},e.ShapeGeometry.prototype.addShape=function(a,b){void 0===b&&(b={});var c,d,f,g=void 0!==b.curveSegments?b.curveSegments:12,h=b.material,i=void 0===b.UVGenerator?e.ExtrudeGeometry.WorldUVGenerator:b.UVGenerator,j=(this.shapebb,this.vertices.length),k=a.extractPoints(g),l=k.shape,m=k.holes,n=!e.Shape.Utils.isClockWise(l);if(n){for(l=l.reverse(),c=0,d=m.length;d>c;c++)f=m[c],e.Shape.Utils.isClockWise(f)&&(m[c]=f.reverse());n=!1}var o=e.Shape.Utils.triangulateShape(l,m),p=l;for(c=0,d=m.length;d>c;c++)f=m[c],l=l.concat(f);{var q,r,s=l.length,t=o.length;p.length}for(c=0;s>c;c++)q=l[c],this.vertices.push(new e.Vector3(q.x,q.y,0));for(c=0;t>c;c++){r=o[c];var u=r[0]+j,v=r[1]+j,w=r[2]+j;this.faces.push(new e.Face3(u,v,w,null,null,h)),this.faceVertexUvs[0].push(i.generateBottomUV(this,a,b,u,v,w))}},e.LatheGeometry=function(a,b,c,d){e.Geometry.call(this),b=b||12,c=c||0,d=d||2*Math.PI;for(var f=1/(a.length-1),g=1/b,h=0,i=b;i>=h;h++)for(var j=c+h*g*d,k=Math.cos(j),l=Math.sin(j),m=0,n=a.length;n>m;m++){var o=a[m],p=new e.Vector3;p.x=k*o.x-l*o.y,p.y=l*o.x+k*o.y,p.z=o.z,this.vertices.push(p)}for(var q=a.length,h=0,i=b;i>h;h++)for(var m=0,n=a.length-1;n>m;m++){var r=m+q*h,s=r,t=r+q,k=r+1+q,u=r+1,v=h*g,w=m*f,x=v+g,y=w+f;this.faces.push(new e.Face3(s,t,u)),this.faceVertexUvs[0].push([new e.Vector2(v,w),new e.Vector2(x,w),new e.Vector2(v,y)]),this.faces.push(new e.Face3(t,k,u)),this.faceVertexUvs[0].push([new e.Vector2(x,w),new e.Vector2(x,y),new e.Vector2(v,y)])}this.mergeVertices(),this.computeCentroids(),this.computeFaceNormals(),this.computeVertexNormals()},e.LatheGeometry.prototype=Object.create(e.Geometry.prototype),e.PlaneGeometry=function(a,b,c,d){e.Geometry.call(this),this.width=a,this.height=b,this.widthSegments=c||1,this.heightSegments=d||1;var f,g,h=a/2,i=b/2,j=this.widthSegments,k=this.heightSegments,l=j+1,m=k+1,n=this.width/j,o=this.height/k,p=new e.Vector3(0,0,1);for(g=0;m>g;g++)for(f=0;l>f;f++){var q=f*n-h,r=g*o-i;this.vertices.push(new e.Vector3(q,-r,0))}for(g=0;k>g;g++)for(f=0;j>f;f++){var s=f+l*g,t=f+l*(g+1),u=f+1+l*(g+1),v=f+1+l*g,w=new e.Vector2(f/j,1-g/k),x=new e.Vector2(f/j,1-(g+1)/k),y=new e.Vector2((f+1)/j,1-(g+1)/k),z=new e.Vector2((f+1)/j,1-g/k),A=new e.Face3(s,t,v);A.normal.copy(p),A.vertexNormals.push(p.clone(),p.clone(),p.clone()),this.faces.push(A),this.faceVertexUvs[0].push([w,x,z]),A=new e.Face3(t,u,v),A.normal.copy(p),A.vertexNormals.push(p.clone(),p.clone(),p.clone()),this.faces.push(A),this.faceVertexUvs[0].push([x.clone(),y,z.clone()])}this.computeCentroids()},e.PlaneGeometry.prototype=Object.create(e.Geometry.prototype),e.RingGeometry=function(a,b,c,d,f,g){e.Geometry.call(this),a=a||0,b=b||50,f=void 0!==f?f:0,g=void 0!==g?g:2*Math.PI,c=void 0!==c?Math.max(3,c):8,d=void 0!==d?Math.max(3,d):8;var h,i,j=[],k=a,l=(b-a)/d;for(h=0;d>=h;h++){for(i=0;c>=i;i++){var m=new e.Vector3,n=f+i/c*g;m.x=k*Math.cos(n),m.y=k*Math.sin(n),this.vertices.push(m),j.push(new e.Vector2((m.x/b+1)/2,(m.y/b+1)/2))}k+=l}var o=new e.Vector3(0,0,1);for(h=0;d>h;h++){var p=h*c;for(i=0;c>=i;i++){var n=i+p,q=n+h,r=n+c+h,s=n+c+1+h;this.faces.push(new e.Face3(q,r,s,[o.clone(),o.clone(),o.clone()])),this.faceVertexUvs[0].push([j[q].clone(),j[r].clone(),j[s].clone()]),q=n+h,r=n+c+1+h,s=n+1+h,this.faces.push(new e.Face3(q,r,s,[o.clone(),o.clone(),o.clone()])),this.faceVertexUvs[0].push([j[q].clone(),j[r].clone(),j[s].clone()])}}this.computeCentroids(),this.computeFaceNormals(),this.boundingSphere=new e.Sphere(new e.Vector3,k)},e.RingGeometry.prototype=Object.create(e.Geometry.prototype),e.SphereGeometry=function(a,b,c,d,f,g,h){e.Geometry.call(this),this.radius=a=a||50,this.widthSegments=b=Math.max(3,Math.floor(b)||8),this.heightSegments=c=Math.max(2,Math.floor(c)||6),this.phiStart=d=void 0!==d?d:0,this.phiLength=f=void 0!==f?f:2*Math.PI,this.thetaStart=g=void 0!==g?g:0,this.thetaLength=h=void 0!==h?h:Math.PI;var i,j,k=[],l=[];for(j=0;c>=j;j++){var m=[],n=[];for(i=0;b>=i;i++){var o=i/b,p=j/c,q=new e.Vector3;q.x=-a*Math.cos(d+o*f)*Math.sin(g+p*h),q.y=a*Math.cos(g+p*h),q.z=a*Math.sin(d+o*f)*Math.sin(g+p*h),this.vertices.push(q),m.push(this.vertices.length-1),n.push(new e.Vector2(o,1-p))}k.push(m),l.push(n)}for(j=0;jp;p++)for(this.grid[p]=[],k=p/(C-1),o=a.getPointAt(k),h=F[p],i=G[p],j=H[p],q=0;q=h&&(g=h,m.set(1,0,0)),g>=i&&(g=i,m.set(0,1,0)),g>=j&&m.set(0,0,1),q.crossVectors(n[0],m).normalize(),o[0].crossVectors(n[0],q),p[0].crossVectors(n[0],o[0])}var f,g,h,i,j,k,l,m=(new e.Vector3,new e.Vector3),n=(new e.Vector3,[]),o=[],p=[],q=new e.Vector3,r=new e.Matrix4,s=b+1,t=1e-4;for(this.tangents=n,this.normals=o,this.binormals=p,k=0;s>k;k++)l=k/(s-1),n[k]=a.getTangentAt(l),n[k].normalize();for(d(),k=1;s>k;k++)o[k]=o[k-1].clone(),p[k]=p[k-1].clone(),q.crossVectors(n[k-1],n[k]),q.length()>t&&(q.normalize(),f=Math.acos(e.Math.clamp(n[k-1].dot(n[k]),-1,1)),o[k].applyMatrix4(r.makeRotationAxis(q,f))),p[k].crossVectors(n[k],o[k]);if(c)for(f=Math.acos(e.Math.clamp(o[0].dot(o[s-1]),-1,1)),f/=s-1,n[0].dot(q.crossVectors(o[0],o[s-1]))>0&&(f=-f),k=1;s>k;k++)o[k].applyMatrix4(r.makeRotationAxis(n[k],f*k)),p[k].crossVectors(n[k],o[k])},e.PolyhedronGeometry=function(a,b,c,d){function f(a){var b=a.normalize().clone();b.index=l.vertices.push(b)-1;var c=i(a)/2/Math.PI+.5,d=j(a)/Math.PI+.5;return b.uv=new e.Vector2(c,1-d),b}function g(a,b,c){var d=new e.Face3(a.index,b.index,c.index,[a.clone(),b.clone(),c.clone()]);d.centroid.add(a).add(b).add(c).divideScalar(3),l.faces.push(d);var f=i(d.centroid);l.faceVertexUvs[0].push([k(a.uv,a,f),k(b.uv,b,f),k(c.uv,c,f)])}function h(a,b){for(var c=Math.pow(2,b),d=(Math.pow(4,b),f(l.vertices[a.a])),e=f(l.vertices[a.b]),h=f(l.vertices[a.c]),i=[],j=0;c>=j;j++){i[j]=[];for(var k=f(d.clone().lerp(h,j/c)),m=f(e.clone().lerp(h,j/c)),n=c-j,o=0;n>=o;o++)i[j][o]=0==o&&j==c?k:f(k.clone().lerp(m,o/n))}for(var j=0;c>j;j++)for(var o=0;2*(c-j)-1>o;o++){var p=Math.floor(o/2);o%2==0?g(i[j][p+1],i[j+1][p],i[j][p]):g(i[j][p+1],i[j+1][p+1],i[j+1][p])}}function i(a){return Math.atan2(a.z,-a.x)}function j(a){return Math.atan2(-a.y,Math.sqrt(a.x*a.x+a.z*a.z))}function k(a,b,c){return 0>c&&1===a.x&&(a=new e.Vector2(a.x-1,a.y)),0===b.x&&0===b.z&&(a=new e.Vector2(c/2/Math.PI+.5,a.y)),a.clone()}e.Geometry.call(this),c=c||1,d=d||0;for(var l=this,m=0,n=a.length;n>m;m++)f(new e.Vector3(a[m][0],a[m][1],a[m][2]));for(var o=this.vertices,p=[],m=0,n=b.length;n>m;m++){var q=o[b[m][0]],r=o[b[m][1]],s=o[b[m][2]];p[m]=new e.Face3(q.index,r.index,s.index,[q.clone(),r.clone(),s.clone()])}for(var m=0,n=p.length;n>m;m++)h(p[m],d);for(var m=0,n=this.faceVertexUvs[0].length;n>m;m++){var t=this.faceVertexUvs[0][m],u=t[0].x,v=t[1].x,w=t[2].x,x=Math.max(u,Math.max(v,w)),y=Math.min(u,Math.min(v,w));x>.9&&.1>y&&(.2>u&&(t[0].x+=1),.2>v&&(t[1].x+=1),.2>w&&(t[2].x+=1))}for(var m=0,n=this.vertices.length;n>m;m++)this.vertices[m].multiplyScalar(c);this.mergeVertices(),this.computeCentroids(),this.computeFaceNormals(),this.boundingSphere=new e.Sphere(new e.Vector3,c)},e.PolyhedronGeometry.prototype=Object.create(e.Geometry.prototype),e.IcosahedronGeometry=function(a,b){this.radius=a,this.detail=b;var c=(1+Math.sqrt(5))/2,d=[[-1,c,0],[1,c,0],[-1,-c,0],[1,-c,0],[0,-1,c],[0,1,c],[0,-1,-c],[0,1,-c],[c,0,-1],[c,0,1],[-c,0,-1],[-c,0,1]],f=[[0,11,5],[0,5,1],[0,1,7],[0,7,10],[0,10,11],[1,5,9],[5,11,4],[11,10,2],[10,7,6],[7,1,8],[3,9,4],[3,4,2],[3,2,6],[3,6,8],[3,8,9],[4,9,5],[2,4,11],[6,2,10],[8,6,7],[9,8,1]];e.PolyhedronGeometry.call(this,d,f,a,b)},e.IcosahedronGeometry.prototype=Object.create(e.Geometry.prototype),e.OctahedronGeometry=function(a,b){var c=[[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]],d=[[0,2,4],[0,4,3],[0,3,5],[0,5,2],[1,2,5],[1,5,3],[1,3,4],[1,4,2]];e.PolyhedronGeometry.call(this,c,d,a,b)},e.OctahedronGeometry.prototype=Object.create(e.Geometry.prototype),e.TetrahedronGeometry=function(a,b){var c=[[1,1,1],[-1,-1,1],[-1,1,-1],[1,-1,-1]],d=[[2,1,0],[0,3,2],[1,3,0],[2,3,1]];e.PolyhedronGeometry.call(this,c,d,a,b)},e.TetrahedronGeometry.prototype=Object.create(e.Geometry.prototype),e.ParametricGeometry=function(a,b,c){e.Geometry.call(this);var d,f,g,h,i,j=this.vertices,k=this.faces,l=this.faceVertexUvs[0],m=b+1;for(d=0;c>=d;d++)for(i=d/c,f=0;b>=f;f++)h=f/b,g=a(h,i),j.push(g);var n,o,p,q,r,s,t,u;for(d=0;c>d;d++)for(f=0;b>f;f++)n=d*m+f,o=d*m+f+1,p=(d+1)*m+f+1,q=(d+1)*m+f,r=new e.Vector2(f/b,d/c),s=new e.Vector2((f+1)/b,d/c),t=new e.Vector2((f+1)/b,(d+1)/c),u=new e.Vector2(f/b,(d+1)/c),k.push(new e.Face3(n,o,q)),l.push([r,s,u]),k.push(new e.Face3(o,p,q)),l.push([s.clone(),t,u.clone()]);this.computeCentroids(),this.computeFaceNormals(),this.computeVertexNormals()},e.ParametricGeometry.prototype=Object.create(e.Geometry.prototype),e.AxisHelper=function(a){a=a||1;var b=new e.Geometry;b.vertices.push(new e.Vector3,new e.Vector3(a,0,0),new e.Vector3,new e.Vector3(0,a,0),new e.Vector3,new e.Vector3(0,0,a)),b.colors.push(new e.Color(16711680),new e.Color(16755200),new e.Color(65280),new e.Color(11206400),new e.Color(255),new e.Color(43775));var c=new e.LineBasicMaterial({vertexColors:e.VertexColors});e.Line.call(this,b,c,e.LinePieces)},e.AxisHelper.prototype=Object.create(e.Line.prototype),e.ArrowHelper=function(a,b,c,d,f,g){e.Object3D.call(this),void 0===d&&(d=16776960),void 0===c&&(c=1),void 0===f&&(f=.2*c),void 0===g&&(g=.2*f),this.position=b;var h=new e.Geometry;h.vertices.push(new e.Vector3(0,0,0)),h.vertices.push(new e.Vector3(0,1,0)),this.line=new e.Line(h,new e.LineBasicMaterial({color:d})),this.line.matrixAutoUpdate=!1,this.add(this.line);var i=new e.CylinderGeometry(0,.5,1,5,1);i.applyMatrix((new e.Matrix4).makeTranslation(0,-.5,0)),this.cone=new e.Mesh(i,new e.MeshBasicMaterial({color:d})),this.cone.matrixAutoUpdate=!1,this.add(this.cone),this.setDirection(a),this.setLength(c,f,g)},e.ArrowHelper.prototype=Object.create(e.Object3D.prototype),e.ArrowHelper.prototype.setDirection=function(){var a,b=new e.Vector3;return function(c){c.y>.99999?this.quaternion.set(0,0,0,1):c.y<-.99999?this.quaternion.set(1,0,0,0):(b.set(c.z,0,-c.x).normalize(),a=Math.acos(c.y),this.quaternion.setFromAxisAngle(b,a))}}(),e.ArrowHelper.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a),void 0===c&&(c=.2*b),this.line.scale.set(1,a,1),this.line.updateMatrix(),this.cone.scale.set(c,b,c),this.cone.position.y=a,this.cone.updateMatrix()},e.ArrowHelper.prototype.setColor=function(a){this.line.material.color.setHex(a),this.cone.material.color.setHex(a)},e.BoxHelper=function(a){var b=[new e.Vector3(1,1,1),new e.Vector3(-1,1,1),new e.Vector3(-1,-1,1),new e.Vector3(1,-1,1),new e.Vector3(1,1,-1),new e.Vector3(-1,1,-1),new e.Vector3(-1,-1,-1),new e.Vector3(1,-1,-1)];this.vertices=b;var c=new e.Geometry;c.vertices.push(b[0],b[1],b[1],b[2],b[2],b[3],b[3],b[0],b[4],b[5],b[5],b[6],b[6],b[7],b[7],b[4],b[0],b[4],b[1],b[5],b[2],b[6],b[3],b[7]),e.Line.call(this,c,new e.LineBasicMaterial({color:16776960}),e.LinePieces),void 0!==a&&this.update(a)},e.BoxHelper.prototype=Object.create(e.Line.prototype),e.BoxHelper.prototype.update=function(a){var b=a.geometry;null===b.boundingBox&&b.computeBoundingBox();var c=b.boundingBox.min,d=b.boundingBox.max,e=this.vertices;e[0].set(d.x,d.y,d.z),e[1].set(c.x,d.y,d.z),e[2].set(c.x,c.y,d.z),e[3].set(d.x,c.y,d.z),e[4].set(d.x,d.y,c.z),e[5].set(c.x,d.y,c.z),e[6].set(c.x,c.y,c.z),e[7].set(d.x,c.y,c.z),this.geometry.computeBoundingSphere(),this.geometry.verticesNeedUpdate=!0,this.matrixAutoUpdate=!1,this.matrixWorld=a.matrixWorld},e.BoundingBoxHelper=function(a,b){var c=void 0!==b?b:8947848;this.object=a,this.box=new e.Box3,e.Mesh.call(this,new e.BoxGeometry(1,1,1),new e.MeshBasicMaterial({color:c,wireframe:!0}))},e.BoundingBoxHelper.prototype=Object.create(e.Mesh.prototype),e.BoundingBoxHelper.prototype.update=function(){this.box.setFromObject(this.object),this.box.size(this.scale),this.box.center(this.position)},e.CameraHelper=function(a){function b(a,b,d){c(a,d),c(b,d)}function c(a,b){d.vertices.push(new e.Vector3),d.colors.push(new e.Color(b)),void 0===g[a]&&(g[a]=[]),g[a].push(d.vertices.length-1)}var d=new e.Geometry,f=new e.LineBasicMaterial({color:16777215,vertexColors:e.FaceColors}),g={},h=16755200,i=16711680,j=43775,k=16777215,l=3355443;b("n1","n2",h),b("n2","n4",h),b("n4","n3",h),b("n3","n1",h),b("f1","f2",h),b("f2","f4",h),b("f4","f3",h),b("f3","f1",h),b("n1","f1",h),b("n2","f2",h),b("n3","f3",h),b("n4","f4",h),b("p","n1",i),b("p","n2",i),b("p","n3",i),b("p","n4",i),b("u1","u2",j),b("u2","u3",j),b("u3","u1",j),b("c","t",k),b("p","c",l),b("cn1","cn2",l),b("cn3","cn4",l),b("cf1","cf2",l),b("cf3","cf4",l),e.Line.call(this,d,f,e.LinePieces),this.camera=a,this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1,this.pointMap=g,this.update()},e.CameraHelper.prototype=Object.create(e.Line.prototype),e.CameraHelper.prototype.update=function(){var a=new e.Vector3,b=new e.Camera,c=new e.Projector;return function(){function d(d,f,g,h){a.set(f,g,h),c.unprojectVector(a,b);var i=e.pointMap[d];if(void 0!==i)for(var j=0,k=i.length;k>j;j++)e.geometry.vertices[i[j]].copy(a)}var e=this,f=1,g=1;b.projectionMatrix.copy(this.camera.projectionMatrix),d("c",0,0,-1),d("t",0,0,1),d("n1",-f,-g,-1),d("n2",f,-g,-1),d("n3",-f,g,-1),d("n4",f,g,-1),d("f1",-f,-g,1),d("f2",f,-g,1),d("f3",-f,g,1),d("f4",f,g,1),d("u1",.7*f,1.1*g,-1),d("u2",.7*-f,1.1*g,-1),d("u3",0,2*g,-1),d("cf1",-f,0,1),d("cf2",f,0,1),d("cf3",0,-g,1),d("cf4",0,g,1),d("cn1",-f,0,-1),d("cn2",f,0,-1),d("cn3",0,-g,-1),d("cn4",0,g,-1),this.geometry.verticesNeedUpdate=!0}}(),e.DirectionalLightHelper=function(a,b){e.Object3D.call(this),this.light=a,this.light.updateMatrixWorld(),this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1,b=b||1;var c=new e.PlaneGeometry(b,b),d=new e.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity),this.lightPlane=new e.Mesh(c,d),this.add(this.lightPlane),c=new e.Geometry,c.vertices.push(new e.Vector3),c.vertices.push(new e.Vector3),d=new e.LineBasicMaterial({fog:!1}),d.color.copy(this.light.color).multiplyScalar(this.light.intensity),this.targetLine=new e.Line(c,d),this.add(this.targetLine),this.update()},e.DirectionalLightHelper.prototype=Object.create(e.Object3D.prototype),e.DirectionalLightHelper.prototype.dispose=function(){this.lightPlane.geometry.dispose(),this.lightPlane.material.dispose(),this.targetLine.geometry.dispose(),this.targetLine.material.dispose()},e.DirectionalLightHelper.prototype.update=function(){var a=new e.Vector3,b=new e.Vector3,c=new e.Vector3;return function(){a.setFromMatrixPosition(this.light.matrixWorld),b.setFromMatrixPosition(this.light.target.matrixWorld),c.subVectors(b,a),this.lightPlane.lookAt(c),this.lightPlane.material.color.copy(this.light.color).multiplyScalar(this.light.intensity),this.targetLine.geometry.vertices[1].copy(c),this.targetLine.geometry.verticesNeedUpdate=!0,this.targetLine.material.color.copy(this.lightPlane.material.color)}}(),e.EdgesHelper=function(a,b){var c=void 0!==b?b:16777215,d=[0,0],f={},g=function(a,b){return a-b},h=["a","b","c"],i=new e.BufferGeometry,j=a.geometry.clone();j.mergeVertices(),j.computeFaceNormals();for(var k=j.vertices,l=j.faces,m=0,n=0,o=l.length;o>n;n++)for(var p=l[n],q=0;3>q;q++){d[0]=p[h[q]],d[1]=p[h[(q+1)%3]],d.sort(g);var r=d.toString();void 0===f[r]?(f[r]={vert1:d[0],vert2:d[1],face1:n,face2:void 0},m++):f[r].face2=n}i.addAttribute("position",Float32Array,2*m,3);var s=i.attributes.position.array,t=0;for(var r in f){var u=f[r];if(void 0===u.face2||l[u.face1].normal.dot(l[u.face2].normal)<.9999){var v=k[u.vert1];s[t++]=v.x,s[t++]=v.y,s[t++]=v.z,v=k[u.vert2],s[t++]=v.x,s[t++]=v.y,s[t++]=v.z}}e.Line.call(this,i,new e.LineBasicMaterial({color:c}),e.LinePieces),this.matrixAutoUpdate=!1,this.matrixWorld=a.matrixWorld},e.EdgesHelper.prototype=Object.create(e.Line.prototype),e.FaceNormalsHelper=function(a,b,c,d){this.object=a,this.size=void 0!==b?b:1;for(var f=void 0!==c?c:16776960,g=void 0!==d?d:1,h=new e.Geometry,i=this.object.geometry.faces,j=0,k=i.length;k>j;j++)h.vertices.push(new e.Vector3),h.vertices.push(new e.Vector3);e.Line.call(this,h,new e.LineBasicMaterial({color:f,linewidth:g}),e.LinePieces),this.matrixAutoUpdate=!1,this.normalMatrix=new e.Matrix3,this.update()},e.FaceNormalsHelper.prototype=Object.create(e.Line.prototype),e.FaceNormalsHelper.prototype.update=function(){var a=new e.Vector3;return function(){this.object.updateMatrixWorld(!0),this.normalMatrix.getNormalMatrix(this.object.matrixWorld);for(var b=this.geometry.vertices,c=this.object.geometry.faces,d=this.object.matrixWorld,e=0,f=c.length;f>e;e++){var g=c[e];a.copy(g.normal).applyMatrix3(this.normalMatrix).normalize().multiplyScalar(this.size);var h=2*e;b[h].copy(g.centroid).applyMatrix4(d),b[h+1].addVectors(b[h],a)}return this.geometry.verticesNeedUpdate=!0,this}}(),e.GridHelper=function(a,b){var c=new e.Geometry,d=new e.LineBasicMaterial({vertexColors:e.VertexColors});this.color1=new e.Color(4473924),this.color2=new e.Color(8947848);for(var f=-a;a>=f;f+=b){c.vertices.push(new e.Vector3(-a,0,f),new e.Vector3(a,0,f),new e.Vector3(f,0,-a),new e.Vector3(f,0,a));var g=0===f?this.color1:this.color2;c.colors.push(g,g,g,g)}e.Line.call(this,c,d,e.LinePieces)},e.GridHelper.prototype=Object.create(e.Line.prototype),e.GridHelper.prototype.setColors=function(a,b){this.color1.set(a),this.color2.set(b),this.geometry.colorsNeedUpdate=!0},e.HemisphereLightHelper=function(a,b){e.Object3D.call(this),this.light=a,this.light.updateMatrixWorld(),this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1,this.colors=[new e.Color,new e.Color];var c=new e.SphereGeometry(b,4,2);c.applyMatrix((new e.Matrix4).makeRotationX(-Math.PI/2));for(var d=0,f=8;f>d;d++)c.faces[d].color=this.colors[4>d?0:1];var g=new e.MeshBasicMaterial({vertexColors:e.FaceColors,wireframe:!0});this.lightSphere=new e.Mesh(c,g),this.add(this.lightSphere),this.update()},e.HemisphereLightHelper.prototype=Object.create(e.Object3D.prototype),e.HemisphereLightHelper.prototype.dispose=function(){this.lightSphere.geometry.dispose(),this.lightSphere.material.dispose()},e.HemisphereLightHelper.prototype.update=function(){var a=new e.Vector3;return function(){this.colors[0].copy(this.light.color).multiplyScalar(this.light.intensity),this.colors[1].copy(this.light.groundColor).multiplyScalar(this.light.intensity),this.lightSphere.lookAt(a.setFromMatrixPosition(this.light.matrixWorld).negate()),this.lightSphere.geometry.colorsNeedUpdate=!0}}(),e.PointLightHelper=function(a,b){this.light=a,this.light.updateMatrixWorld();var c=new e.SphereGeometry(b,4,2),d=new e.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity),e.Mesh.call(this,c,d),this.matrixWorld=this.light.matrixWorld,this.matrixAutoUpdate=!1},e.PointLightHelper.prototype=Object.create(e.Mesh.prototype),e.PointLightHelper.prototype.dispose=function(){this.geometry.dispose(),this.material.dispose()},e.PointLightHelper.prototype.update=function(){this.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)},e.SpotLightHelper=function(a){e.Object3D.call(this),this.light=a,this.light.updateMatrixWorld(),this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1;var b=new e.CylinderGeometry(0,1,1,8,1,!0);b.applyMatrix((new e.Matrix4).makeTranslation(0,-.5,0)),b.applyMatrix((new e.Matrix4).makeRotationX(-Math.PI/2));var c=new e.MeshBasicMaterial({wireframe:!0,fog:!1});this.cone=new e.Mesh(b,c),this.add(this.cone),this.update()},e.SpotLightHelper.prototype=Object.create(e.Object3D.prototype),e.SpotLightHelper.prototype.dispose=function(){this.cone.geometry.dispose(),this.cone.material.dispose()},e.SpotLightHelper.prototype.update=function(){var a=new e.Vector3,b=new e.Vector3;return function(){var c=this.light.distance?this.light.distance:1e4,d=c*Math.tan(this.light.angle);this.cone.scale.set(d,d,c),a.setFromMatrixPosition(this.light.matrixWorld),b.setFromMatrixPosition(this.light.target.matrixWorld),this.cone.lookAt(b.sub(a)),this.cone.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)}}(),e.VertexNormalsHelper=function(a,b,c,d){this.object=a,this.size=void 0!==b?b:1;for(var f=void 0!==c?c:16711680,g=void 0!==d?d:1,h=new e.Geometry,i=(a.geometry.vertices,a.geometry.faces),j=0,k=i.length;k>j;j++)for(var l=i[j],m=0,n=l.vertexNormals.length;n>m;m++)h.vertices.push(new e.Vector3),h.vertices.push(new e.Vector3);e.Line.call(this,h,new e.LineBasicMaterial({color:f,linewidth:g}),e.LinePieces),this.matrixAutoUpdate=!1,this.normalMatrix=new e.Matrix3,this.update()},e.VertexNormalsHelper.prototype=Object.create(e.Line.prototype),e.VertexNormalsHelper.prototype.update=function(){var a=new e.Vector3;return function(){var b=["a","b","c","d"];this.object.updateMatrixWorld(!0),this.normalMatrix.getNormalMatrix(this.object.matrixWorld);for(var c=this.geometry.vertices,d=this.object.geometry.vertices,e=this.object.geometry.faces,f=this.object.matrixWorld,g=0,h=0,i=e.length;i>h;h++)for(var j=e[h],k=0,l=j.vertexNormals.length;l>k;k++){var m=j[b[k]],n=d[m],o=j.vertexNormals[k];c[g].copy(n).applyMatrix4(f),a.copy(o).applyMatrix3(this.normalMatrix).normalize().multiplyScalar(this.size),a.add(c[g]),g+=1,c[g].copy(a),g+=1}return this.geometry.verticesNeedUpdate=!0,this}}(),e.VertexTangentsHelper=function(a,b,c,d){this.object=a,this.size=void 0!==b?b:1;for(var f=void 0!==c?c:255,g=void 0!==d?d:1,h=new e.Geometry,i=(a.geometry.vertices,a.geometry.faces),j=0,k=i.length;k>j;j++)for(var l=i[j],m=0,n=l.vertexTangents.length;n>m;m++)h.vertices.push(new e.Vector3),h.vertices.push(new e.Vector3);e.Line.call(this,h,new e.LineBasicMaterial({color:f,linewidth:g}),e.LinePieces),this.matrixAutoUpdate=!1,this.update()},e.VertexTangentsHelper.prototype=Object.create(e.Line.prototype),e.VertexTangentsHelper.prototype.update=function(){var a=new e.Vector3;return function(){var b=["a","b","c","d"];this.object.updateMatrixWorld(!0);for(var c=this.geometry.vertices,d=this.object.geometry.vertices,e=this.object.geometry.faces,f=this.object.matrixWorld,g=0,h=0,i=e.length;i>h;h++)for(var j=e[h],k=0,l=j.vertexTangents.length;l>k;k++){var m=j[b[k]],n=d[m],o=j.vertexTangents[k];c[g].copy(n).applyMatrix4(f),a.copy(o).transformDirection(f).multiplyScalar(this.size),a.add(c[g]),g+=1,c[g].copy(a),g+=1}return this.geometry.verticesNeedUpdate=!0,this}}(),e.WireframeHelper=function(a,b){var c=void 0!==b?b:16777215,d=[0,0],f={},g=function(a,b){return a-b},h=["a","b","c"],i=new e.BufferGeometry;if(a.geometry instanceof e.Geometry){for(var j=a.geometry.vertices,k=a.geometry.faces,l=0,m=new Uint32Array(6*k.length),n=0,o=k.length;o>n;n++)for(var p=k[n],q=0;3>q;q++){d[0]=p[h[q]],d[1]=p[h[(q+1)%3]],d.sort(g);var r=d.toString();void 0===f[r]&&(m[2*l]=d[0],m[2*l+1]=d[1],f[r]=!0,l++)}i.addAttribute("position",Float32Array,2*l,3);for(var s=i.attributes.position.array,n=0,o=l;o>n;n++)for(var q=0;2>q;q++){var t=j[m[2*n+q]],u=6*n+3*q;s[u+0]=t.x,s[u+1]=t.y,s[u+2]=t.z}}else if(a.geometry instanceof e.BufferGeometry&&void 0!==a.geometry.attributes.index){for(var j=a.geometry.attributes.position.array,v=a.geometry.attributes.index.array,w=a.geometry.offsets,l=0,m=new Uint32Array(2*v.length),x=0,y=w.length;y>x;++x)for(var z=w[x].start,A=w[x].count,u=w[x].index,n=z,B=z+A;B>n;n+=3)for(var q=0;3>q;q++){d[0]=u+v[n+q],d[1]=u+v[n+(q+1)%3],d.sort(g);var r=d.toString();void 0===f[r]&&(m[2*l]=d[0],m[2*l+1]=d[1],f[r]=!0,l++)}i.addAttribute("position",Float32Array,2*l,3);for(var s=i.attributes.position.array,n=0,o=l;o>n;n++)for(var q=0;2>q;q++){var u=6*n+3*q,C=3*m[2*n+q];s[u+0]=j[C],s[u+1]=j[C+1],s[u+2]=j[C+2]}}else if(a.geometry instanceof e.BufferGeometry){var j=a.geometry.attributes.position.array,l=j.length/3,D=l/3;i.addAttribute("position",Float32Array,2*l,3);for(var s=i.attributes.position.array,n=0,o=D;o>n;n++)for(var q=0;3>q;q++){var u=18*n+6*q,E=9*n+3*q;s[u+0]=j[E],s[u+1]=j[E+1],s[u+2]=j[E+2];var C=9*n+3*((q+1)%3);s[u+3]=j[C],s[u+4]=j[C+1],s[u+5]=j[C+2]}}e.Line.call(this,i,new e.LineBasicMaterial({color:c}),e.LinePieces),this.matrixAutoUpdate=!1,this.matrixWorld=a.matrixWorld},e.WireframeHelper.prototype=Object.create(e.Line.prototype),e.ImmediateRenderObject=function(){e.Object3D.call(this),this.render=function(){}},e.ImmediateRenderObject.prototype=Object.create(e.Object3D.prototype),e.LensFlare=function(a,b,c,d,f){e.Object3D.call(this),this.lensFlares=[],this.positionScreen=new e.Vector3,this.customUpdateCallback=void 0,void 0!==a&&this.add(a,b,c,d,f)},e.LensFlare.prototype=Object.create(e.Object3D.prototype),e.LensFlare.prototype.add=function(a,b,c,d,f,g){void 0===b&&(b=-1),void 0===c&&(c=0),void 0===g&&(g=1),void 0===f&&(f=new e.Color(16777215)),void 0===d&&(d=e.NormalBlending),c=Math.min(c,Math.max(0,c)),this.lensFlares.push({texture:a,size:b,distance:c,x:0,y:0,z:0,scale:1,rotation:1,opacity:g,color:f,blending:d})},e.LensFlare.prototype.updateLensFlares=function(){var a,b,c=this.lensFlares.length,d=2*-this.positionScreen.x,e=2*-this.positionScreen.y;for(a=0;c>a;a++)b=this.lensFlares[a],b.x=this.positionScreen.x+d*b.distance,b.y=this.positionScreen.y+e*b.distance,b.wantedRotation=b.x*Math.PI*.25,b.rotation+=.25*(b.wantedRotation-b.rotation)},e.MorphBlendMesh=function(a,b){e.Mesh.call(this,a,b),this.animationsMap={},this.animationsList=[];var c=this.geometry.morphTargets.length,d="__default",f=0,g=c-1,h=c/1;this.createAnimation(d,f,g,h),this.setAnimationWeight(d,1)},e.MorphBlendMesh.prototype=Object.create(e.Mesh.prototype),e.MorphBlendMesh.prototype.createAnimation=function(a,b,c,d){var e={startFrame:b,endFrame:c,length:c-b+1,fps:d,duration:(c-b)/d,lastFrame:0,currentFrame:0,active:!1,time:0,direction:1,weight:1,directionBackwards:!1,mirroredLoop:!1};this.animationsMap[a]=e,this.animationsList.push(e)},e.MorphBlendMesh.prototype.autoCreateAnimations=function(a){for(var b,c=/([a-z]+)(\d+)/,d={},e=this.geometry,f=0,g=e.morphTargets.length;g>f;f++){var h=e.morphTargets[f],i=h.name.match(c);if(i&&i.length>1){{var j=i[1];i[2]}d[j]||(d[j]={start:1/0,end:-1/0});var k=d[j];fk.end&&(k.end=f),b||(b=j)}}for(var j in d){var k=d[j];this.createAnimation(j,k.start,k.end,a)}this.firstAnimation=b},e.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){var b=this.animationsMap[a];b&&(b.direction=1,b.directionBackwards=!1)},e.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){var b=this.animationsMap[a];b&&(b.direction=-1,b.directionBackwards=!0)},e.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)},e.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)},e.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)},e.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)},e.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0,c=this.animationsMap[a];return c&&(b=c.time),b},e.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1,c=this.animationsMap[a];return c&&(b=c.duration),b},e.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):console.warn("animation["+a+"] undefined")},e.MorphBlendMesh.prototype.stopAnimation=function(a){var b=this.animationsMap[a];b&&(b.active=!1)},e.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;c>b;b++){var d=this.animationsList[b];if(d.active){var f=d.duration/d.length;d.time+=d.direction*a,d.mirroredLoop?(d.time>d.duration||d.time<0)&&(d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),d.time<0&&(d.time=0,d.directionBackwards=!1)):(d.time=d.time%d.duration,d.time<0&&(d.time+=d.duration));var g=d.startFrame+e.Math.clamp(Math.floor(d.time/f),0,d.length-1),h=d.weight;g!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*h,this.morphTargetInfluences[g]=0,d.lastFrame=d.currentFrame,d.currentFrame=g);var i=d.time%f/f;d.directionBackwards&&(i=1-i),this.morphTargetInfluences[d.currentFrame]=i*h,this.morphTargetInfluences[d.lastFrame]=(1-i)*h}}},e.LensFlarePlugin=function(){function a(a,c){var d=b.createProgram(),e=b.createShader(b.FRAGMENT_SHADER),f=b.createShader(b.VERTEX_SHADER),g="precision "+c+" float;\n";return b.shaderSource(e,g+a.fragmentShader),b.shaderSource(f,g+a.vertexShader),b.compileShader(e),b.compileShader(f),b.attachShader(d,e),b.attachShader(d,f),b.linkProgram(d),d}var b,c,d,f={};this.init=function(g){b=g.context,c=g,d=g.getPrecision(),f.vertices=new Float32Array(16),f.faces=new Uint16Array(6);var h=0;f.vertices[h++]=-1,f.vertices[h++]=-1,f.vertices[h++]=0,f.vertices[h++]=0,f.vertices[h++]=1,f.vertices[h++]=-1,f.vertices[h++]=1,f.vertices[h++]=0,f.vertices[h++]=1,f.vertices[h++]=1,f.vertices[h++]=1,f.vertices[h++]=1,f.vertices[h++]=-1,f.vertices[h++]=1,f.vertices[h++]=0,f.vertices[h++]=1,h=0,f.faces[h++]=0,f.faces[h++]=1,f.faces[h++]=2,f.faces[h++]=0,f.faces[h++]=2,f.faces[h++]=3,f.vertexBuffer=b.createBuffer(),f.elementBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,f.vertexBuffer),b.bufferData(b.ARRAY_BUFFER,f.vertices,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,f.elementBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,f.faces,b.STATIC_DRAW),f.tempTexture=b.createTexture(),f.occlusionTexture=b.createTexture(),b.bindTexture(b.TEXTURE_2D,f.tempTexture),b.texImage2D(b.TEXTURE_2D,0,b.RGB,16,16,0,b.RGB,b.UNSIGNED_BYTE,null),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST),b.bindTexture(b.TEXTURE_2D,f.occlusionTexture),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,16,16,0,b.RGBA,b.UNSIGNED_BYTE,null),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST),b.getParameter(b.MAX_VERTEX_TEXTURE_IMAGE_UNITS)<=0?(f.hasVertexTexture=!1,f.program=a(e.ShaderFlares.lensFlare,d)):(f.hasVertexTexture=!0,f.program=a(e.ShaderFlares.lensFlareVertexTexture,d)),f.attributes={},f.uniforms={},f.attributes.vertex=b.getAttribLocation(f.program,"position"),f.attributes.uv=b.getAttribLocation(f.program,"uv"),f.uniforms.renderType=b.getUniformLocation(f.program,"renderType"),f.uniforms.map=b.getUniformLocation(f.program,"map"),f.uniforms.occlusionMap=b.getUniformLocation(f.program,"occlusionMap"),f.uniforms.opacity=b.getUniformLocation(f.program,"opacity"),f.uniforms.color=b.getUniformLocation(f.program,"color"),f.uniforms.scale=b.getUniformLocation(f.program,"scale"),f.uniforms.rotation=b.getUniformLocation(f.program,"rotation"),f.uniforms.screenPosition=b.getUniformLocation(f.program,"screenPosition")},this.render=function(a,d,g,h){var i=a.__webglFlares,j=i.length;if(j){var k=new e.Vector3,l=h/g,m=.5*g,n=.5*h,o=16/h,p=new e.Vector2(o*l,o),q=new e.Vector3(1,1,0),r=new e.Vector2(1,1),s=f.uniforms,t=f.attributes;b.useProgram(f.program),b.enableVertexAttribArray(f.attributes.vertex),b.enableVertexAttribArray(f.attributes.uv),b.uniform1i(s.occlusionMap,0),b.uniform1i(s.map,1),b.bindBuffer(b.ARRAY_BUFFER,f.vertexBuffer),b.vertexAttribPointer(t.vertex,2,b.FLOAT,!1,16,0),b.vertexAttribPointer(t.uv,2,b.FLOAT,!1,16,8),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,f.elementBuffer),b.disable(b.CULL_FACE),b.depthMask(!1);var u,v,w,x,y;for(u=0;j>u;u++)if(o=16/h,p.set(o*l,o),x=i[u],k.set(x.matrixWorld.elements[12],x.matrixWorld.elements[13],x.matrixWorld.elements[14]),k.applyMatrix4(d.matrixWorldInverse),k.applyProjection(d.projectionMatrix),q.copy(k),r.x=q.x*m+m,r.y=q.y*n+n,f.hasVertexTexture||r.x>0&&r.x0&&r.yv;v++)y=x.lensFlares[v],y.opacity>.001&&y.scale>.001&&(q.x=y.x,q.y=y.y,q.z=y.z,o=y.size*y.scale/h,p.x=o*l,p.y=o,b.uniform3f(s.screenPosition,q.x,q.y,q.z),b.uniform2f(s.scale,p.x,p.y),b.uniform1f(s.rotation,y.rotation),b.uniform1f(s.opacity,y.opacity),b.uniform3f(s.color,y.color.r,y.color.g,y.color.b),c.setBlending(y.blending,y.blendEquation,y.blendSrc,y.blendDst),c.setTexture(y.texture,1),b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0)); -b.enable(b.CULL_FACE),b.enable(b.DEPTH_TEST),b.depthMask(!0)}}},e.ShadowMapPlugin=function(){function a(a,b){var c=new e.DirectionalLight;c.isVirtual=!0,c.onlyShadow=!0,c.castShadow=!0,c.shadowCameraNear=a.shadowCameraNear,c.shadowCameraFar=a.shadowCameraFar,c.shadowCameraLeft=a.shadowCameraLeft,c.shadowCameraRight=a.shadowCameraRight,c.shadowCameraBottom=a.shadowCameraBottom,c.shadowCameraTop=a.shadowCameraTop,c.shadowCameraVisible=a.shadowCameraVisible,c.shadowDarkness=a.shadowDarkness,c.shadowBias=a.shadowCascadeBias[b],c.shadowMapWidth=a.shadowCascadeWidth[b],c.shadowMapHeight=a.shadowCascadeHeight[b],c.pointsWorld=[],c.pointsFrustum=[];for(var d=c.pointsWorld,f=c.pointsFrustum,g=0;8>g;g++)d[g]=new e.Vector3,f[g]=new e.Vector3;var h=a.shadowCascadeNearZ[b],i=a.shadowCascadeFarZ[b];return f[0].set(-1,-1,h),f[1].set(1,-1,h),f[2].set(-1,1,h),f[3].set(1,1,h),f[4].set(-1,-1,i),f[5].set(1,-1,i),f[6].set(-1,1,i),f[7].set(1,1,i),c}function b(a,b){var c=a.shadowCascadeArray[b];c.position.copy(a.position),c.target.position.copy(a.target.position),c.lookAt(c.target),c.shadowCameraVisible=a.shadowCameraVisible,c.shadowDarkness=a.shadowDarkness,c.shadowBias=a.shadowCascadeBias[b];var d=a.shadowCascadeNearZ[b],e=a.shadowCascadeFarZ[b],f=c.pointsFrustum;f[0].z=d,f[1].z=d,f[2].z=d,f[3].z=d,f[4].z=e,f[5].z=e,f[6].z=e,f[7].z=e}function c(a,b){var c=b.shadowCamera,d=b.pointsFrustum,f=b.pointsWorld;n.set(1/0,1/0,1/0),o.set(-1/0,-1/0,-1/0);for(var g=0;8>g;g++){var h=f[g];h.copy(d[g]),e.ShadowMapPlugin.__projector.unprojectVector(h,a),h.applyMatrix4(c.matrixWorldInverse),h.xo.x&&(o.x=h.x),h.yo.y&&(o.y=h.y),h.zo.z&&(o.z=h.z)}c.left=n.x,c.right=o.x,c.top=o.y,c.bottom=n.y,c.updateProjectionMatrix()}function d(a){return a.material instanceof e.MeshFaceMaterial?a.material.materials[0]:a.material}var f,g,h,i,j,k,l=new e.Frustum,m=new e.Matrix4,n=new e.Vector3,o=new e.Vector3,p=new e.Vector3;this.init=function(a){f=a.context,g=a;var b=e.ShaderLib.depthRGBA,c=e.UniformsUtils.clone(b.uniforms);h=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c}),i=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c,morphTargets:!0}),j=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c,skinning:!0}),k=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c,morphTargets:!0,skinning:!0}),h._shadowPass=!0,i._shadowPass=!0,j._shadowPass=!0,k._shadowPass=!0},this.render=function(a,b){g.shadowMapEnabled&&g.shadowMapAutoUpdate&&this.update(a,b)},this.update=function(n,o){var q,r,s,t,u,v,w,x,y,z,A,B,C,D,E=[],F=0,G=null;for(f.clearColor(1,1,1,1),f.disable(f.BLEND),f.enable(f.CULL_FACE),f.frontFace(f.CCW),f.cullFace(g.shadowMapCullFace===e.CullFaceFront?f.FRONT:f.BACK),g.setDepthTest(!0),q=0,r=n.__lights.length;r>q;q++)if(C=n.__lights[q],C.castShadow)if(C instanceof e.DirectionalLight&&C.shadowCascade)for(u=0;uq;q++){if(C=E[q],!C.shadowMap){var J=e.LinearFilter;g.shadowMapType===e.PCFSoftShadowMap&&(J=e.NearestFilter);var K={minFilter:J,magFilter:J,format:e.RGBAFormat};C.shadowMap=new e.WebGLRenderTarget(C.shadowMapWidth,C.shadowMapHeight,K),C.shadowMapSize=new e.Vector2(C.shadowMapWidth,C.shadowMapHeight),C.shadowMatrix=new e.Matrix4}if(!C.shadowCamera){if(C instanceof e.SpotLight)C.shadowCamera=new e.PerspectiveCamera(C.shadowCameraFov,C.shadowMapWidth/C.shadowMapHeight,C.shadowCameraNear,C.shadowCameraFar);else{if(!(C instanceof e.DirectionalLight)){console.error("Unsupported light type for shadow");continue}C.shadowCamera=new e.OrthographicCamera(C.shadowCameraLeft,C.shadowCameraRight,C.shadowCameraTop,C.shadowCameraBottom,C.shadowCameraNear,C.shadowCameraFar)}n.add(C.shadowCamera),n.autoUpdate===!0&&n.updateMatrixWorld()}for(C.shadowCameraVisible&&!C.cameraHelper&&(C.cameraHelper=new e.CameraHelper(C.shadowCamera),C.shadowCamera.add(C.cameraHelper)),C.isVirtual&&H.originalCamera==o&&c(o,C),v=C.shadowMap,w=C.shadowMatrix,x=C.shadowCamera,x.position.setFromMatrixPosition(C.matrixWorld),p.setFromMatrixPosition(C.target.matrixWorld),x.lookAt(p),x.updateMatrixWorld(),x.matrixWorldInverse.getInverse(x.matrixWorld),C.cameraHelper&&(C.cameraHelper.visible=C.shadowCameraVisible),C.shadowCameraVisible&&C.cameraHelper.update(),w.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1),w.multiply(x.projectionMatrix),w.multiply(x.matrixWorldInverse),m.multiplyMatrices(x.projectionMatrix,x.matrixWorldInverse),l.setFromMatrix(m),g.setRenderTarget(v),g.clear(),D=n.__webglObjects,s=0,t=D.length;t>s;s++)A=D[s],B=A.object,A.render=!1,B.visible&&B.castShadow&&((B instanceof e.Mesh||B instanceof e.ParticleSystem)&&B.frustumCulled&&!l.intersectsObject(B)||(B._modelViewMatrix.multiplyMatrices(x.matrixWorldInverse,B.matrixWorld),A.render=!0));var L,M,N;for(s=0,t=D.length;t>s;s++)A=D[s],A.render&&(B=A.object,y=A.buffer,L=d(B),M=void 0!==B.geometry.morphTargets&&B.geometry.morphTargets.length>0&&L.morphTargets,N=B instanceof e.SkinnedMesh&&L.skinning,z=B.customDepthMaterial?B.customDepthMaterial:N?M?k:j:M?i:h,y instanceof e.BufferGeometry?g.renderBufferDirect(x,n.__lights,G,z,y,B):g.renderBuffer(x,n.__lights,G,z,y,B));for(D=n.__webglObjectsImmediate,s=0,t=D.length;t>s;s++)A=D[s],B=A.object,B.visible&&B.castShadow&&(B._modelViewMatrix.multiplyMatrices(x.matrixWorldInverse,B.matrixWorld),g.renderImmediateObject(x,n.__lights,G,h,B))}var O=g.getClearColor(),P=g.getClearAlpha();f.clearColor(O.r,O.g,O.b,P),f.enable(f.BLEND),g.shadowMapCullFace===e.CullFaceFront&&f.cullFace(f.BACK)}},e.ShadowMapPlugin.__projector=new e.Projector,e.SpritePlugin=function(){function a(){var a=c.createProgram(),b=c.createShader(c.VERTEX_SHADER),e=c.createShader(c.FRAGMENT_SHADER);return c.shaderSource(b,["precision "+d.getPrecision()+" float;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform float rotation;","uniform vec2 scale;","uniform vec2 uvOffset;","uniform vec2 uvScale;","attribute vec2 position;","attribute vec2 uv;","varying vec2 vUV;","void main() {","vUV = uvOffset + uv * uvScale;","vec2 alignedPosition = position * scale;","vec2 rotatedPosition;","rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;","rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;","vec4 finalPosition;","finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );","finalPosition.xy += rotatedPosition;","finalPosition = projectionMatrix * finalPosition;","gl_Position = finalPosition;","}"].join("\n")),c.shaderSource(e,["precision "+d.getPrecision()+" float;","uniform vec3 color;","uniform sampler2D map;","uniform float opacity;","uniform int fogType;","uniform vec3 fogColor;","uniform float fogDensity;","uniform float fogNear;","uniform float fogFar;","uniform float alphaTest;","varying vec2 vUV;","void main() {","vec4 texture = texture2D( map, vUV );","if ( texture.a < alphaTest ) discard;","gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );","if ( fogType > 0 ) {","float depth = gl_FragCoord.z / gl_FragCoord.w;","float fogFactor = 0.0;","if ( fogType == 1 ) {","fogFactor = smoothstep( fogNear, fogFar, depth );","} else {","const float LOG2 = 1.442695;","float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );","fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );","}","gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );","}","}"].join("\n")),c.compileShader(b),c.compileShader(e),c.attachShader(a,b),c.attachShader(a,e),c.linkProgram(a),a}function b(a,b){return a.z!==b.z?b.z-a.z:b.id-a.id}var c,d,f,g,h,i,j,k,l,m;this.init=function(b){c=b.context,d=b,g=new Float32Array([-.5,-.5,0,0,.5,-.5,1,0,.5,.5,1,1,-.5,.5,0,1]),h=new Uint16Array([0,1,2,0,2,3]),i=c.createBuffer(),j=c.createBuffer(),c.bindBuffer(c.ARRAY_BUFFER,i),c.bufferData(c.ARRAY_BUFFER,g,c.STATIC_DRAW),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,j),c.bufferData(c.ELEMENT_ARRAY_BUFFER,h,c.STATIC_DRAW),k=a(),l={position:c.getAttribLocation(k,"position"),uv:c.getAttribLocation(k,"uv")},m={uvOffset:c.getUniformLocation(k,"uvOffset"),uvScale:c.getUniformLocation(k,"uvScale"),rotation:c.getUniformLocation(k,"rotation"),scale:c.getUniformLocation(k,"scale"),color:c.getUniformLocation(k,"color"),map:c.getUniformLocation(k,"map"),opacity:c.getUniformLocation(k,"opacity"),modelViewMatrix:c.getUniformLocation(k,"modelViewMatrix"),projectionMatrix:c.getUniformLocation(k,"projectionMatrix"),fogType:c.getUniformLocation(k,"fogType"),fogDensity:c.getUniformLocation(k,"fogDensity"),fogNear:c.getUniformLocation(k,"fogNear"),fogFar:c.getUniformLocation(k,"fogFar"),fogColor:c.getUniformLocation(k,"fogColor"),alphaTest:c.getUniformLocation(k,"alphaTest")};var n=document.createElement("canvas");n.width=8,n.height=8;var o=n.getContext("2d");o.fillStyle="#ffffff",o.fillRect(0,0,n.width,n.height),f=new e.Texture(n),f.needsUpdate=!0},this.render=function(a,g){var h=a.__webglSprites,n=h.length;if(n){c.useProgram(k),c.enableVertexAttribArray(l.position),c.enableVertexAttribArray(l.uv),c.disable(c.CULL_FACE),c.enable(c.BLEND),c.bindBuffer(c.ARRAY_BUFFER,i),c.vertexAttribPointer(l.position,2,c.FLOAT,!1,16,0),c.vertexAttribPointer(l.uv,2,c.FLOAT,!1,16,8),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,j),c.uniformMatrix4fv(m.projectionMatrix,!1,g.projectionMatrix.elements),c.activeTexture(c.TEXTURE0),c.uniform1i(m.map,0);var o=0,p=0,q=a.fog;q?(c.uniform3f(m.fogColor,q.color.r,q.color.g,q.color.b),q instanceof e.Fog?(c.uniform1f(m.fogNear,q.near),c.uniform1f(m.fogFar,q.far),c.uniform1i(m.fogType,1),o=1,p=1):q instanceof e.FogExp2&&(c.uniform1f(m.fogDensity,q.density),c.uniform1i(m.fogType,2),o=2,p=2)):(c.uniform1i(m.fogType,0),o=0,p=0);var r,s,t,u,v=[];for(r=0;n>r;r++)s=h[r],t=s.material,s.visible!==!1&&(s._modelViewMatrix.multiplyMatrices(g.matrixWorldInverse,s.matrixWorld),s.z=-s._modelViewMatrix.elements[14]);for(h.sort(b),r=0;n>r;r++)s=h[r],s.visible!==!1&&(t=s.material,c.uniform1f(m.alphaTest,t.alphaTest),c.uniformMatrix4fv(m.modelViewMatrix,!1,s._modelViewMatrix.elements),v[0]=s.scale.x,v[1]=s.scale.y,u=a.fog&&t.fog?p:0,o!==u&&(c.uniform1i(m.fogType,u),o=u),null!==t.map?(c.uniform2f(m.uvOffset,t.map.offset.x,t.map.offset.y),c.uniform2f(m.uvScale,t.map.repeat.x,t.map.repeat.y)):(c.uniform2f(m.uvOffset,0,0),c.uniform2f(m.uvScale,1,1)),c.uniform1f(m.opacity,t.opacity),c.uniform3f(m.color,t.color.r,t.color.g,t.color.b),c.uniform1f(m.rotation,t.rotation),c.uniform2fv(m.scale,v),d.setBlending(t.blending,t.blendEquation,t.blendSrc,t.blendDst),d.setDepthTest(t.depthTest),d.setDepthWrite(t.depthWrite),t.map&&t.map.image&&t.map.image.width?d.setTexture(t.map,0):d.setTexture(f,0),c.drawElements(c.TRIANGLES,6,c.UNSIGNED_SHORT,0));c.enable(c.CULL_FACE)}}},e.DepthPassPlugin=function(){function a(a){return a.material instanceof e.MeshFaceMaterial?a.material.materials[0]:a.material}this.enabled=!1,this.renderTarget=null;var b,c,d,f,g,h,i=new e.Frustum,j=new e.Matrix4;this.init=function(a){b=a.context,c=a;var i=e.ShaderLib.depthRGBA,j=e.UniformsUtils.clone(i.uniforms);d=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j}),f=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j,morphTargets:!0}),g=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j,skinning:!0}),h=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j,morphTargets:!0,skinning:!0}),d._shadowPass=!0,f._shadowPass=!0,g._shadowPass=!0,h._shadowPass=!0},this.render=function(a,b){this.enabled&&this.update(a,b)},this.update=function(k,l){var m,n,o,p,q,r,s,t=null;for(b.clearColor(1,1,1,1),b.disable(b.BLEND),c.setDepthTest(!0),k.autoUpdate===!0&&k.updateMatrixWorld(),l.matrixWorldInverse.getInverse(l.matrixWorld),j.multiplyMatrices(l.projectionMatrix,l.matrixWorldInverse),i.setFromMatrix(j),c.setRenderTarget(this.renderTarget),c.clear(),s=k.__webglObjects,m=0,n=s.length;n>m;m++)q=s[m],r=q.object,q.render=!1,r.visible&&((r instanceof e.Mesh||r instanceof e.ParticleSystem)&&r.frustumCulled&&!i.intersectsObject(r)||(r._modelViewMatrix.multiplyMatrices(l.matrixWorldInverse,r.matrixWorld),q.render=!0));var u,v,w;for(m=0,n=s.length;n>m;m++)if(q=s[m],q.render){if(r=q.object,o=q.buffer,r instanceof e.ParticleSystem&&!r.customDepthMaterial)continue;u=a(r),u&&c.setMaterialFaces(r.material),v=r.geometry.morphTargets.length>0&&u.morphTargets,w=r instanceof e.SkinnedMesh&&u.skinning,p=r.customDepthMaterial?r.customDepthMaterial:w?v?h:g:v?f:d,o instanceof e.BufferGeometry?c.renderBufferDirect(l,k.__lights,t,p,o,r):c.renderBuffer(l,k.__lights,t,p,o,r)}for(s=k.__webglObjectsImmediate,m=0,n=s.length;n>m;m++)q=s[m],r=q.object,r.visible&&(r._modelViewMatrix.multiplyMatrices(l.matrixWorldInverse,r.matrixWorld),c.renderImmediateObject(l,k.__lights,t,d,r));var x=c.getClearColor(),y=c.getClearAlpha();b.clearColor(x.r,x.g,x.b,y),b.enable(b.BLEND)}},e.ShaderFlares={lensFlareVertexTexture:{vertexShader:["uniform lowp int renderType;","uniform vec3 screenPosition;","uniform vec2 scale;","uniform float rotation;","uniform sampler2D occlusionMap;","attribute vec2 position;","attribute vec2 uv;","varying vec2 vUV;","varying float vVisibility;","void main() {","vUV = uv;","vec2 pos = position;","if( renderType == 2 ) {","vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );","visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );","visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );","visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );","visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );","visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );","visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );","visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );","visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );","vVisibility = visibility.r / 9.0;","vVisibility *= 1.0 - visibility.g / 9.0;","vVisibility *= visibility.b / 9.0;","vVisibility *= 1.0 - visibility.a / 9.0;","pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;","pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;","}","gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );","}"].join("\n"),fragmentShader:["uniform lowp int renderType;","uniform sampler2D map;","uniform float opacity;","uniform vec3 color;","varying vec2 vUV;","varying float vVisibility;","void main() {","if( renderType == 0 ) {","gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );","} else if( renderType == 1 ) {","gl_FragColor = texture2D( map, vUV );","} else {","vec4 texture = texture2D( map, vUV );","texture.a *= opacity * vVisibility;","gl_FragColor = texture;","gl_FragColor.rgb *= color;","}","}"].join("\n")},lensFlare:{vertexShader:["uniform lowp int renderType;","uniform vec3 screenPosition;","uniform vec2 scale;","uniform float rotation;","attribute vec2 position;","attribute vec2 uv;","varying vec2 vUV;","void main() {","vUV = uv;","vec2 pos = position;","if( renderType == 2 ) {","pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;","pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;","}","gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );","}"].join("\n"),fragmentShader:["precision mediump float;","uniform lowp int renderType;","uniform sampler2D map;","uniform sampler2D occlusionMap;","uniform float opacity;","uniform vec3 color;","varying vec2 vUV;","void main() {","if( renderType == 0 ) {","gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );","} else if( renderType == 1 ) {","gl_FragColor = texture2D( map, vUV );","} else {","float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;","visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;","visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;","visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;","visibility = ( 1.0 - visibility / 4.0 );","vec4 texture = texture2D( map, vUV );","texture.a *= opacity * visibility;","gl_FragColor = texture;","gl_FragColor.rgb *= color;","}","}"].join("\n")}},"undefined"!=typeof c?("undefined"!=typeof b&&b.exports&&(c=b.exports=e),c.THREE=e):this.THREE=e},{}],13:[function(a,b){void 0===Date.now&&(Date.now=function(){return(new Date).valueOf()});var c=c||function(){var a=[];return{REVISION:"13",getAll:function(){return a},removeAll:function(){a=[]},add:function(b){a.push(b)},remove:function(b){var c=a.indexOf(b);-1!==c&&a.splice(c,1)},update:function(b){if(0===a.length)return!1;var c=0;for(b=void 0!==b?b:"undefined"!=typeof window&&void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now();ca;a++)p[a].stop()},this.delay=function(a){return l=a,this},this.repeat=function(a){return h=a,this},this.yoyo=function(a){return i=a,this},this.easing=function(a){return n=a,this},this.interpolation=function(a){return o=a,this},this.chain=function(){return p=arguments,this},this.onStart=function(a){return q=a,this},this.onUpdate=function(a){return s=a,this},this.onComplete=function(a){return t=a,this},this.onStop=function(a){return u=a,this},this.update=function(a){var c;if(m>a)return!0;r===!1&&(null!==q&&q.call(b),r=!0);var j=(a-m)/g;j=j>1?1:j;var u=n(j);for(c in e){var v=d[c]||0,w=e[c];w instanceof Array?b[c]=o(w,u):("string"==typeof w&&(w=v+parseFloat(w,10)),"number"==typeof w&&(b[c]=v+(w-v)*u))}if(null!==s&&s.call(b,u),1==j){if(h>0){isFinite(h)&&h--;for(c in f){if("string"==typeof e[c]&&(f[c]=f[c]+parseFloat(e[c],10)),i){var x=f[c];f[c]=e[c],e[c]=x}d[c]=f[c]}return i&&(k=!k),m=a+l,!0}null!==t&&t.call(b);for(var y=0,z=p.length;z>y;y++)p[y].start(a);return!1}return!0}},c.Easing={Linear:{None:function(a){return a}},Quadratic:{In:function(a){return a*a},Out:function(a){return a*(2-a)},InOut:function(a){return(a*=2)<1?.5*a*a:-.5*(--a*(a-2)-1)}},Cubic:{In:function(a){return a*a*a},Out:function(a){return--a*a*a+1},InOut:function(a){return(a*=2)<1?.5*a*a*a:.5*((a-=2)*a*a+2)}},Quartic:{In:function(a){return a*a*a*a},Out:function(a){return 1- --a*a*a*a},InOut:function(a){return(a*=2)<1?.5*a*a*a*a:-.5*((a-=2)*a*a*a-2)}},Quintic:{In:function(a){return a*a*a*a*a},Out:function(a){return--a*a*a*a*a+1},InOut:function(a){return(a*=2)<1?.5*a*a*a*a*a:.5*((a-=2)*a*a*a*a+2)}},Sinusoidal:{In:function(a){return 1-Math.cos(a*Math.PI/2)},Out:function(a){return Math.sin(a*Math.PI/2)},InOut:function(a){return.5*(1-Math.cos(Math.PI*a))}},Exponential:{In:function(a){return 0===a?0:Math.pow(1024,a-1)},Out:function(a){return 1===a?1:1-Math.pow(2,-10*a)},InOut:function(a){return 0===a?0:1===a?1:(a*=2)<1?.5*Math.pow(1024,a-1):.5*(-Math.pow(2,-10*(a-1))+2)}},Circular:{In:function(a){return 1-Math.sqrt(1-a*a)},Out:function(a){return Math.sqrt(1- --a*a)},InOut:function(a){return(a*=2)<1?-.5*(Math.sqrt(1-a*a)-1):.5*(Math.sqrt(1-(a-=2)*a)+1)}},Elastic:{In:function(a){var b,c=.1,d=.4;return 0===a?0:1===a?1:(!c||1>c?(c=1,b=d/4):b=d*Math.asin(1/c)/(2*Math.PI),-(c*Math.pow(2,10*(a-=1))*Math.sin(2*(a-b)*Math.PI/d)))},Out:function(a){var b,c=.1,d=.4;return 0===a?0:1===a?1:(!c||1>c?(c=1,b=d/4):b=d*Math.asin(1/c)/(2*Math.PI),c*Math.pow(2,-10*a)*Math.sin(2*(a-b)*Math.PI/d)+1)},InOut:function(a){var b,c=.1,d=.4;return 0===a?0:1===a?1:(!c||1>c?(c=1,b=d/4):b=d*Math.asin(1/c)/(2*Math.PI),(a*=2)<1?-.5*c*Math.pow(2,10*(a-=1))*Math.sin(2*(a-b)*Math.PI/d):c*Math.pow(2,-10*(a-=1))*Math.sin(2*(a-b)*Math.PI/d)*.5+1)}},Back:{In:function(a){var b=1.70158;return a*a*((b+1)*a-b)},Out:function(a){var b=1.70158;return--a*a*((b+1)*a+b)+1},InOut:function(a){var b=2.5949095;return(a*=2)<1?.5*a*a*((b+1)*a-b):.5*((a-=2)*a*((b+1)*a+b)+2)}},Bounce:{In:function(a){return 1-c.Easing.Bounce.Out(1-a)},Out:function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375},InOut:function(a){return.5>a?.5*c.Easing.Bounce.In(2*a):.5*c.Easing.Bounce.Out(2*a-1)+.5}}},c.Interpolation={Linear:function(a,b){var d=a.length-1,e=d*b,f=Math.floor(e),g=c.Interpolation.Utils.Linear;return 0>b?g(a[0],a[1],e):b>1?g(a[d],a[d-1],d-e):g(a[f],a[f+1>d?d:f+1],e-f)},Bezier:function(a,b){var d,e=0,f=a.length-1,g=Math.pow,h=c.Interpolation.Utils.Bernstein;for(d=0;f>=d;d++)e+=g(1-b,f-d)*g(b,d)*a[d]*h(f,d);return e},CatmullRom:function(a,b){var d=a.length-1,e=d*b,f=Math.floor(e),g=c.Interpolation.Utils.CatmullRom;return a[0]===a[d]?(0>b&&(f=Math.floor(e=d*(1+b))),g(a[(f-1+d)%d],a[f],a[(f+1)%d],a[(f+2)%d],e-f)):0>b?a[0]-(g(a[0],a[0],a[1],a[1],-e)-a[0]):b>1?a[d]-(g(a[d],a[d],a[d-1],a[d-1],e-d)-a[d]):g(a[f?f-1:0],a[f],a[f+1>d?d:f+1],a[f+2>d?d:f+2],e-f)},Utils:{Linear:function(a,b,c){return(b-a)*c+a},Bernstein:function(a,b){var d=c.Interpolation.Utils.Factorial;return d(a)/d(b)/d(a-b)},Factorial:function(){var a=[1];return function(b){var c,d=1;if(a[b])return a[b];for(c=b;c>1;c--)d*=c;return a[b]=d}}(),CatmullRom:function(a,b,c,d,e){var f=.5*(c-a),g=.5*(d-b),h=e*e,i=e*h;return(2*b-2*c+f+g)*i+(-3*b+3*c-2*f-g)*h+f*e+b}}},b.exports=c},{}],14:[function(a,b){!function c(a,d,e){function f(a,b){return this instanceof f?(g(a)?(b=a[1],a=a[0]):"object"==typeof a&&a&&(b=a.y,a=a.x),this.x=f.clean(a||0),void(this.y=f.clean(b||0))):new f(a,b)}var g=function(a){return"[object Array]"===Object.prototype.toString.call(a)};f.prototype={change:function(a){if("function"==typeof a)this.observers?this.observers.push(a):this.observers=[a];else if(this.observers&&this.observers.length)for(var b=this.observers.length-1;b>=0;b--)this.observers[b](this,a);return this},ignore:function(a){if(this.observers)if(a)for(var b=this.observers,c=b.length;c--;)b[c]===a&&b.splice(c,1);else this.observers=[];return this},set:function(a,b,c){if("number"!=typeof a&&(c=b,b=a.y,a=a.x),this.x===a&&this.y===b)return this;var d=null;return c!==!1&&this.observers&&this.observers.length&&(d=this.clone()),this.x=f.clean(a),this.y=f.clean(b),c!==!1?this.change(d):void 0},zero:function(){return this.set(0,0)},clone:function(){return new this.constructor(this.x,this.y)},negate:function(a){return a?new this.constructor(-this.x,-this.y):this.set(-this.x,-this.y)},add:function(a,b,c){return"number"!=typeof a&&(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)),a+=this.x,b+=this.y,c?new this.constructor(a,b):this.set(a,b)},subtract:function(a,b,c){return"number"!=typeof a&&(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)),a=this.x-a,b=this.y-b,c?new this.constructor(a,b):this.set(a,b)},multiply:function(a,b,c){return"number"!=typeof a?(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)):"number"!=typeof b&&(c=b,b=a),a*=this.x,b*=this.y,c?new this.constructor(a,b):this.set(a,b)},rotate:function(a,b,c){var d,e,f=this.x,g=this.y,h=Math.cos(a),i=Math.sin(a);return b=b?-1:1,d=h*f-b*i*g,e=b*i*f+h*g,c?new this.constructor(d,e):this.set(d,e)},length:function(){var a=this.x,b=this.y;return Math.sqrt(a*a+b*b)},lengthSquared:function(){var a=this.x,b=this.y;return a*a+b*b},distance:function(a){var b=this.x-a.x,c=this.y-a.y;return Math.sqrt(b*b+c*c)},normalize:function(a){var b=this.length(),c=bc?c:e,h=f>d?d:f;return b?new this.constructor(g,h):this.set(g,h)},max:function(a,b){var c=this.x,d=this.y,e=a.x,f=a.y,g=c>e?c:e,h=d>f?d:f;return b?new this.constructor(g,h):this.set(g,h)},clamp:function(a,b,c){var d=this.min(b,!0).max(a);return c?d:this.set(d.x,d.y)},lerp:function(a,b,c){return this.add(a.subtract(this,!0).multiply(b),c)},skew:function(a){return a?new this.constructor(-this.y,this.x):this.set(-this.y,this.x)},dot:function(a){return f.clean(this.x*a.x+a.y*this.y)},perpDot:function(a){return f.clean(this.x*a.y-this.y*a.x)},angleTo:function(a){return Math.atan2(this.perpDot(a),this.dot(a))},divide:function(a,b,c){if("number"!=typeof a?(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)):"number"!=typeof b&&(c=b,b=a),0===a||0===b)throw new Error("division by zero");if(isNaN(a)||isNaN(b))throw new Error("NaN detected");return c?new this.constructor(this.x/a,this.y/b):this.set(this.x/a,this.y/b)},isPointOnLine:function(a,b){return(a.y-this.y)*(a.x-b.x)===(a.y-b.y)*(a.x-this.x)},toArray:function(){return[this.x,this.y]},fromArray:function(a){return this.set(a[0],a[1])},toJSON:function(){return{x:this.x,y:this.y}},toString:function(){return"("+this.x+", "+this.y+")"},constructor:f},f.fromArray=function(a,b){return new(b||f)(a[0],a[1])},f.precision=d||8;var h=Math.pow(10,f.precision);return f.clean=a||function(a){if(isNaN(a))throw new Error("NaN detected");if(!isFinite(a))throw new Error("Infinity detected");return Math.round(a)===a?a:Math.round(a*h)/h},f.inject=c,a||(f.fast=c(function(a){return a}),"undefined"!=typeof b&&"object"==typeof b.exports?b.exports=f:window.Vec2=window.Vec2||f),f}()},{}],15:[function(a,b){function c(a,b,c){c||(c={}),this.width=a,this.height=b,this.points=[],this.introLines=new e.Object3D,this.pins=[],this.markers=[],this.satelliteAnimations=[],this.satelliteMeshes=[],this.satellites={},this.quadtree=new f(new g(180,360),5),this.active=!0;var d={font:"Inconsolata",baseColor:"#ffcc00",markerColor:"#ffcc00",pinColor:"#00eeee",satelliteColor:"#ff0000",blankPercentage:0,thinAntarctica:.01,mapUrl:"resources/equirectangle_projection.png",introLinesAltitude:1.1,introLinesDuration:2e3,introLinesColor:"#8FD8D8",introLinesCount:60,scale:1,dayLength:28e3,pointsPerDegree:1.1,pointSize:.6,pointsVariance:.2,maxPins:500,maxMarkers:4,data:[],tiles:[],viewAngle:0};for(var h in d)this[h]||(this[h]=d[h],c[h]&&(this[h]=c[h]));this.setScale(this.scale),this.renderer=new e.WebGLRenderer({antialias:!0}),this.renderer.setSize(this.width,this.height),this.renderer.gammaInput=!0,this.renderer.gammaOutput=!0,this.domElement=this.renderer.domElement,this.data.sort(function(a,b){return b.lng-2*b.label.length-(a.lng-2*a.label.length)});for(var h=0;h0&&this.firstRunTime+(next=this.data.pop()).when=Date.now()&&this.data.push(next)}},p=function(){this.hexGrid&&this.scene.remove(this.hexGrid);var a=["#define PI 3.141592653589793238462643","#define DISTANCE 500.0","#define INTRODURATION "+(parseFloat(this.introLinesDuration)+1e-5),"#define INTROALTITUDE "+(parseFloat(this.introLinesAltitude)+1e-5),"attribute float lng;","uniform float currentTime;","varying vec4 vColor;","","void main()","{"," vec3 newPos = position;"," float opacityVal = 0.0;"," float introStart = INTRODURATION * ((180.0 + lng)/360.0);"," if(currentTime > introStart){"," opacityVal = 1.0;"," }"," if(currentTime > introStart && currentTime < introStart + INTRODURATION / 8.0){"," newPos = position * INTROALTITUDE;"," opacityVal = .3;"," }"," if(currentTime > introStart + INTRODURATION / 8.0 && currentTime < introStart + INTRODURATION / 8.0 + 200.0){"," newPos = position * (1.0 + ((INTROALTITUDE-1.0) * (1.0-(currentTime - introStart-(INTRODURATION/8.0))/200.0)));"," }"," vColor = vec4( color, opacityVal );"," gl_Position = projectionMatrix * modelViewMatrix * vec4(newPos, 1.0);","}"].join("\n"),b=["varying vec4 vColor;","void main()","{"," gl_FragColor = vColor;"," float depth = gl_FragCoord.z / gl_FragCoord.w;"," float fogFactor = smoothstep("+parseInt(this.cameraDistance)+".0,"+parseInt(this.cameraDistance+300)+".0, depth );"," vec3 fogColor = vec3(0.0);"," gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w ), fogFactor );","}"].join("\n"),c={lng:{type:"f",value:null}};this.pointUniforms={currentTime:{type:"f",value:0}};var d=new e.ShaderMaterial({uniforms:this.pointUniforms,attributes:c,vertexShader:a,fragmentShader:b,transparent:!0,vertexColors:e.VertexColors,side:e.DoubleSide}),f=4*this.tiles.length,g=new e.BufferGeometry;g.addAttribute("index",Uint16Array,3*f,1),g.addAttribute("position",Float32Array,3*f,3),g.addAttribute("normal",Float32Array,3*f,3),g.addAttribute("color",Float32Array,3*f,3),g.addAttribute("lng",Float32Array,3*f,1);for(var h=g.attributes.lng.array,i=l(this.baseColor).hueSet(),j=[],k=0;k5&&q(s+3,r.b[0].x,r.b[0].y,r.b[0].z,r.b[5].x,r.b[5].y,r.b[5].z,r.b[4].x,r.b[4].y,r.b[4].z,r.lat,r.lon,v)}g.offsets=[];for(var w=f/m,k=0;w>k;k++){var x={start:k*m*3,index:k*m*3,count:3*Math.min(f-k*m,m)};g.offsets.push(x)}g.computeBoundingSphere(),this.hexGrid=new e.Mesh(g,d),this.scene.add(this.hexGrid)},q=function(){for(var a,b=new e.LineBasicMaterial({color:this.introLinesColor,transparent:!0,linewidth:2,opacity:.5}),c=0;ci;i++){var j=m.mapPoint(f,g-5*i);a=new e.Vector3(j.x*this.introLinesAltitude,j.y*this.introLinesAltitude,j.z*this.introLinesAltitude),d.vertices.push(a)}this.introLines.add(new e.Line(d,b))}this.scene.add(this.introLines)};c.prototype.init=function(a){this.camera=new e.PerspectiveCamera(50,this.width/this.height,1,this.cameraDistance+300),this.camera.position.z=this.cameraDistance,this.cameraAngle=Math.PI,this.scene=new e.Scene,this.scene.fog=new e.Fog(0,this.cameraDistance,this.cameraDistance+300),q.call(this),this.smokeProvider=new k(this.scene),p.call(this),setTimeout(a,500) -},c.prototype.destroy=function(a){var b=this;this.active=!1,setTimeout(function(){for(;b.scene.children.length>0;)b.scene.remove(b.scene.children[0]);"function"==typeof a&&a()},1e3)},c.prototype.addPin=function(a,b,c){a=parseFloat(a),b=parseFloat(b);var d={lineColor:this.pinColor,topColor:this.pinColor},e=1.2;("string"!=typeof c||0===c.length)&&(e-=.05+.05*Math.random());var f=new h(a,b,c,e,this.scene,this.smokeProvider,d);this.pins.push(f);var i=n(a,b);if(f.pos_=new g(parseInt(i.x),parseInt(i.y)),f.rad_=c.length>0?i.rad:1,this.quadtree.addObject(f),c.length>0){var j=this.quadtree.getCollisionsForObject(f),k=0,l=0,m=[];for(var o in j)j[o].text.length>0&&(k++,j[o].age()>5e3?m.push(j[o]):l++);if(k>0&&0==l)for(var o=0;o0&&(f.hideLabel(),f.hideSmoke(),f.hideTop(),f.changeAltitude(.05*Math.random()+1.1))}if(this.pins.length>this.maxPins){var p=this.pins.shift();this.quadtree.removeObject(p),p.remove()}return f},c.prototype.addMarker=function(a,b,c,d){var e,f={markerColor:this.markerColor,lineColor:this.markerColor};return e="boolean"==typeof d&&d?new i(a,b,c,1.2,this.markers[this.markers.length-1],this.scene,f):"object"==typeof d?new i(a,b,c,1.2,d,this.scene,f):new i(a,b,c,1.2,null,this.scene,f),this.markers.push(e),this.markers.length>this.maxMarkers&&this.markers.shift().remove(),e},c.prototype.addSatellite=function(a,b,c,d,e,f){d||(d={}),void 0==d.coreColor&&(d.coreColor=this.satelliteColor);var g=new j(a,b,c,this.scene,d,e,f);return this.satellites[g.toString()]||(this.satellites[g.toString()]=g),g.onRemove(function(){delete this.satellites[g.toString()]}.bind(this)),g},c.prototype.addConstellation=function(a,b){for(var c,d=[],e=0;ethis.maxPins;){var b=this.pins.shift();this.quadtree.removeObject(b),b.remove()}},c.prototype.setMaxMarkers=function(a){for(this.maxMarkers=a;this.markers.length>this.maxMarkers;)this.markers.shift().remove()},c.prototype.setBaseColor=function(a){this.baseColor=a,p.call(this)},c.prototype.setMarkerColor=function(a){this.markerColor=a,this.scene._encom_markerTexture=null},c.prototype.setPinColor=function(a){this.pinColor=a},c.prototype.setScale=function(a){this.scale=a,this.cameraDistance=1700/a,this.scene&&this.scene.fog&&(this.scene.fog.near=this.cameraDistance,this.scene.fog.far=this.cameraDistance+300,p.call(this),this.camera.far=this.cameraDistance+300,this.camera.updateProjectionMatrix())},c.prototype.tick=function(){if(this.camera){this.firstRunTime||(this.firstRunTime=Date.now()),o.call(this),d.update(),this.lastRenderDate||(this.lastRenderDate=new Date),this.firstRenderDate||(this.firstRenderDate=new Date),this.totalRunTime=new Date-this.firstRenderDate;var a=new Date-this.lastRenderDate;this.lastRenderDate=new Date;var b=2*Math.PI/(this.dayLength/a);this.cameraAngle+=b,this.active||(this.cameraDistance+=1e3*a/1e3),this.camera.position.x=this.cameraDistance*Math.cos(this.cameraAngle)*Math.cos(this.viewAngle),this.camera.position.y=Math.sin(this.viewAngle)*this.cameraDistance,this.camera.position.z=this.cameraDistance*Math.sin(this.cameraAngle)*Math.cos(this.viewAngle);for(var c in this.satellites)this.satellites[c].tick(this.camera.position,this.cameraAngle,a);for(var c=0;cthis.totalRunTime?(this.totalRunTime/this.introLinesDuration<.1&&(this.introLines.children[0].material.opacity=this.totalRunTime/this.introLinesDuration*10-.2),this.introLines.children[0].material.opacity=this.totalRunTime/this.introLinesDuration>.8?5*Math.max(1-this.totalRunTime/this.introLinesDuration,0):1,this.introLines.rotateY(2*Math.PI/(this.introLinesDuration/a))):this.introLines&&(this.scene.remove(this.introLines),delete[this.introLines]),this.pointUniforms.currentTime.value=this.totalRunTime,this.smokeProvider.tick(this.totalRunTime),this.camera.lookAt(this.scene.position),this.renderer.render(this.scene,this.camera)}},b.exports=c},{"./Marker":16,"./Pin":17,"./Satellite":18,"./SmokeProvider":19,"./utils":21,"hexasphere.js":3,"pusher.color":6,quadtree2:8,three:12,"tween.js":13,vec2:14}],16:[function(a,b){var c=a("three"),d=a("tween.js"),e=a("./utils"),f=function(a){var b,d,f=30,g=30;return b=e.renderToCanvas(f,g,function(b){b.fillStyle=a,b.strokeStyle=a,b.lineWidth=3,b.beginPath(),b.arc(f/2,g/2,f/3,0,2*Math.PI),b.stroke(),b.beginPath(),b.arc(f/2,g/2,f/5,0,2*Math.PI),b.fill()}),d=new c.Texture(b),d.needsUpdate=!0,d},g=function(a,b,g,h,i,j,k){var l,m,n,o,p,q,r={lineColor:"#FFCC00",lineWidth:1,markerColor:"#FFCC00",labelColor:"#FFF",font:"Inconsolata",fontSize:20,drawTime:2e3,lineSegments:150};if(this.lat=parseFloat(a),this.lon=parseFloat(b),this.text=g,this.altitude=parseFloat(h),this.scene=j,this.previous=i,this.next=[],this.previous&&this.previous.next.push(this),k)for(var s in r)void 0!=k[s]&&(r[s]=k[s]);this.opts=r,l=e.mapPoint(a,b),i&&(m=e.mapPoint(i.lat,i.lon)),j._encom_markerTexture||(j._encom_markerTexture=f(this.opts.markerColor)),n=new c.SpriteMaterial({map:j._encom_markerTexture,opacity:.7,depthTest:!0,fog:!0}),this.marker=new c.Sprite(n),this.marker.scale.set(0,0),this.marker.position.set(l.x*h,l.y*h,l.z*h),o=e.createLabel(g.toUpperCase(),this.opts.fontSize,this.opts.labelColor,this.opts.font,this.opts.markerColor),p=new c.Texture(o),p.needsUpdate=!0,q=new c.SpriteMaterial({map:p,useScreenCoordinates:!1,opacity:0,depthTest:!0,fog:!0}),this.labelSprite=new c.Sprite(q),this.labelSprite.position={x:l.x*h*1.1,y:l.y*h*1.05+(l.y<0?-15:30),z:l.z*h*1.1},this.labelSprite.scale.set(o.width,o.height),new d.Tween({opacity:0}).to({opacity:1},500).onUpdate(function(){q.opacity=this.opacity}).start();var t=this;if(new d.Tween({x:0,y:0}).to({x:50,y:50},2e3).easing(d.Easing.Elastic.Out).onUpdate(function(){t.marker.scale.set(this.x,this.y)}).delay(this.previous?t.opts.drawTime:0).start(),this.previous){var u,v,w,x,y,z,A,B,C,D,E,F,G=[],H=[];t.geometrySpline=new c.Geometry,u=new c.LineBasicMaterial({color:this.opts.lineColor,transparent:!0,linewidth:3,opacity:.5}),t.geometrySplineDotted=new c.Geometry,v=new c.LineBasicMaterial({color:this.opts.lineColor,linewidth:1,transparent:!0,opacity:.5}),w=(a-i.lat)/t.opts.lineSegments,x=(b-i.lon)/t.opts.lineSegments,y=e.mapPoint(i.lat,i.lon),G=[],H=[];for(var I=0;I=a.index&&(E.set(1.2*D.x,1.2*D.y,1.2*D.z),currentVert2.set(1.19*currentPoint2.x,1.19*currentPoint2.y,1.19*currentPoint2.z)),t.geometrySpline.verticesNeedUpdate=!0,t.geometrySplineDotted.verticesNeedUpdate=!0;G.length>0&&setTimeout(F,t.opts.drawTime/t.opts.lineSegments)},F(),this.scene.add(new c.Line(t.geometrySpline,u)),this.scene.add(new c.Line(t.geometrySplineDotted,v,c.LinePieces))}this.scene.add(this.marker),this.scene.add(this.labelSprite)};g.prototype.remove=function(){for(var a=0,b=this,c=function(d){for(var e=0;a>e;e++)d.geometrySpline.vertices[e].set(d.geometrySpline.vertices[e+1]),d.geometrySplineDotted.vertices[e].set(d.geometrySplineDotted.vertices[e+1]),d.geometrySpline.verticesNeedUpdate=!0,d.geometrySplineDotted.verticesNeedUpdate=!0;a++,a0,showTop:g.length>0,showSmoke:g.length>0};if(this.lat=a,this.lon=b,this.text=g,this.altitude=h,this.scene=i,this.smokeProvider=j,this.dateCreated=Date.now(),k)for(var t in s)void 0!=k[t]&&(s[t]=k[t]);this.opts=s,this.topVisible=s.showTop,this.smokeVisible=s.showSmoke,this.labelVisible=s.showLabel,this.lineGeometry=new c.Geometry,l=new c.LineBasicMaterial({color:s.lineColor,linewidth:s.lineWidth}),r=e.mapPoint(a,b),this.lineGeometry.vertices.push(new c.Vector3(r.x,r.y,r.z)),this.lineGeometry.vertices.push(new c.Vector3(r.x,r.y,r.z)),this.line=new c.Line(this.lineGeometry,l),m=e.createLabel(g,18,s.labelColor,s.font),n=new c.Texture(m),n.needsUpdate=!0,o=new c.SpriteMaterial({map:n,useScreenCoordinates:!1,opacity:0,depthTest:!0,fog:!0}),this.labelSprite=new c.Sprite(o),this.labelSprite.position={x:r.x*h*1.1,y:r.y*h+(r.y<0?-15:30),z:r.z*h*1.1},this.labelSprite.scale.set(m.width,m.height),p=new c.Texture(f(s.topColor)),p.needsUpdate=!0,q=new c.SpriteMaterial({map:p,depthTest:!0,fog:!0,opacity:0}),this.topSprite=new c.Sprite(q),this.topSprite.scale.set(20,20),this.topSprite.position.set(r.x*h,r.y*h,r.z*h),this.smokeVisible&&(this.smokeId=j.setFire(a,b,h));var u=this;(s.showTop||s.showLabel)&&new d.Tween({opacity:0}).to({opacity:1},500).onUpdate(function(){q.opacity=u.topVisible?this.opacity:0,o.opacity=u.labelVisible?this.opacity:0}).delay(1e3).start(),new d.Tween(r).to({x:r.x*h,y:r.y*h,z:r.z*h},1500).easing(d.Easing.Elastic.Out).onUpdate(function(){u.lineGeometry.vertices[1].x=this.x,u.lineGeometry.vertices[1].y=this.y,u.lineGeometry.vertices[1].z=this.z,u.lineGeometry.verticesNeedUpdate=!0}).start(),this.scene.add(this.labelSprite),this.scene.add(this.line),this.scene.add(this.topSprite)};g.prototype.toString=function(){return""+this.lat+"_"+this.lon},g.prototype.changeAltitude=function(a){var b=e.mapPoint(this.lat,this.lon),c=this;new d.Tween({altitude:this.altitude}).to({altitude:a},1500).easing(d.Easing.Elastic.Out).onUpdate(function(){c.smokeVisible&&c.smokeProvider.changeAltitude(this.altitude,c.smokeId),c.topVisible&&c.topSprite.position.set(b.x*this.altitude,b.y*this.altitude,b.z*this.altitude),c.labelVisible&&(c.labelSprite.position={x:b.x*this.altitude*1.1,y:b.y*this.altitude+(b.y<0?-15:30),z:b.z*this.altitude*1.1}),c.lineGeometry.vertices[1].x=b.x*this.altitude,c.lineGeometry.vertices[1].y=b.y*this.altitude,c.lineGeometry.vertices[1].z=b.z*this.altitude,c.lineGeometry.verticesNeedUpdate=!0}).onComplete(function(){c.altitude=a}).start()},g.prototype.hideTop=function(){this.topVisible&&(this.topSprite.material.opacity=0,this.topVisible=!1)},g.prototype.showTop=function(){this.topVisible||(this.topSprite.material.opacity=1,this.topVisible=!0)},g.prototype.hideLabel=function(){this.labelVisible&&(this.labelSprite.material.opacity=0,this.labelVisible=!1)},g.prototype.showLabel=function(){this.labelVisible||(this.labelSprite.material.opacity=1,this.labelVisible=!0)},g.prototype.hideSmoke=function(){this.smokeVisible&&(this.smokeProvider.extinguish(this.smokeId),this.smokeVisible=!1)},g.prototype.showSmoke=function(){this.smokeVisible||(this.smokeId=this.smokeProvider.setFire(this.lat,this.lon,this.altitude),this.smokeVisible=!0)},g.prototype.age=function(){return Date.now()-this.dateCreated},g.prototype.remove=function(){this.scene.remove(this.labelSprite),this.scene.remove(this.line),this.scene.remove(this.topSprite),this.smokeVisible&&this.smokeProvider.extinguish(this.smokeId)},b.exports=g},{"./utils":21,three:12,"tween.js":13}],18:[function(a,b){var c=a("./TextureAnimator"),d=a("three"),e=a("./utils"),f=function(a,b,c,d,f,g,h,i){var j=a/c,k=Math.floor((a-d)/f),l=b-25,m=l/(a-d),n=0,o=0,p=0,q=e.hexToRgb(g);return e.renderToCanvas(a*b/c,b*c,function(c){for(var e=0;a>e;e++){e-p*j>=j&&(n=0,o+=b,p++);var g=n+25,l=o+Math.floor(b/2);c.lineWidth=2,c.strokeStyle=i;var r=Math.PI/16,s=-Math.PI+Math.PI/4,t=8,u=Math.floor(a-2*(a-d)/f)+1;d>e&&(t=t*e/d);for(var v=Math.floor((u-d)/2)+d,w=0;4>w;w++){if(c.beginPath(),d>e||e>=a)c.arc(g,l,t,w*Math.PI/2+s+r,w*Math.PI/2+s+Math.PI/2-2*r);else if(e>d&&v>e){var x=v-d,y=3*Math.PI/2,z=e-d,A=y/x,B=-Math.PI+Math.PI/4+r+A*z;c.arc(g,l,t,Math.max(w*Math.PI/2+s,B),Math.max(w*Math.PI/2+s+Math.PI/2-2*r,B+Math.PI/2-2*r))}else if(e>=v&&u>e){var x=u-v,y=2*w*Math.PI/4,z=e-v,A=y/x,B=Math.PI/2+Math.PI/4+r+A*z;c.arc(g,l,t,B,B+Math.PI/2-2*r)}else if(e>=u&&(a-u)/2+u>e){var x=(a-u)/2,y=Math.PI/2,z=e-u,A=y/x,B=w*(Math.PI/2)+Math.PI/4+r+A*z;c.arc(g,l,t,B,B+Math.PI/2-2*r)}else c.arc(g,l,t,w*Math.PI/2+s+r,w*Math.PI/2+s+Math.PI/2-2*r);c.stroke()}for(var C,D=0;f>D;D++)C=e-k*D-d,C>0&&b-25>C*m&&(c.strokeStyle="rgba("+q.r+","+q.g+","+q.b+","+(.9-C*m/(b-25))+")",c.lineWidth=2,c.beginPath(),c.arc(g,l,C*m,-Math.PI/12,Math.PI/12),c.stroke());c.fillStyle="#000",c.beginPath(),c.arc(g,l,3,0,2*Math.PI),c.fill(),c.strokeStyle=h,c.lineWidth=2,c.beginPath(),d>e?c.arc(g,l,3*e/d,0,2*Math.PI):c.arc(g,l,3,0,2*Math.PI),c.stroke(),n+=b}})},g=function(a,b,g,h,i,j,k){var l,m,n,o,p,q,r,s=e.mapPoint(a,b);s.x*=g,s.y*=g,s.z*=g;var m={numWaves:8,waveColor:"#FFF",coreColor:"#FF0000",shieldColor:"#FFF",size:1};if(this.lat=a,this.lon=b,this.altitude=g,this.scene=h,this.onRemoveList=[],n=50,o=100,p=10,q=Math.floor(n/8),i)for(var t in m)void 0!=i[t]&&(m[t]=i[t]);this.opts=m,j?(this.canvas=j,k?this.texture=k:(this.texture=new d.Texture(this.canvas),this.texture.needsUpdate=!0,r=Math.floor(n-2*(n-q)/m.numWaves)+1,this.animator=new c(this.texture,p,n/p,n,80,r))):(this.canvas=f(n,o,p,q,m.numWaves,m.waveColor,m.coreColor,m.shieldColor),this.texture=new d.Texture(this.canvas),this.texture.needsUpdate=!0,r=Math.floor(n-2*(n-q)/m.numWaves)+1,this.animator=new c(this.texture,p,n/p,n,80,r)),l=new d.PlaneGeometry(150*m.size,150*m.size,1,1),this.material=new d.MeshBasicMaterial({map:this.texture,depthTest:!1,transparent:!0}),this.mesh=new d.Mesh(l,this.material),this.mesh.tiltMultiplier=Math.PI/2*(1-Math.abs(a/90)),this.mesh.tiltDirection=a>0?-1:1,this.mesh.lon=b,this.mesh.position.set(s.x,s.y,s.z),this.mesh.rotation.z=-1*(a/90)*Math.PI/2,this.mesh.rotation.y=b/180*Math.PI,h.add(this.mesh)};g.prototype.changeAltitude=function(a){var b=e.mapPoint(this.lat,this.lon);b.x*=a,b.y*=a,b.z*=a,this.altitude=a,this.mesh.position.set(b.x,b.y,b.z)},g.prototype.changeCanvas=function(a,b,e,g){numFrames=50,pixels=100,rows=10,waveStart=Math.floor(numFrames/8),a?this.opts.numWaves=a:a=this.opts.numWaves,b?this.opts.waveColor=b:b=this.opts.waveColor,e?this.opts.coreColor=e:e=this.opts.coreColor,g?this.opts.shieldColor=g:g=this.opts.shieldColor,this.canvas=f(numFrames,pixels,rows,waveStart,a,b,e,g),this.texture=new d.Texture(this.canvas),this.texture.needsUpdate=!0,repeatAt=Math.floor(numFrames-2*(numFrames-waveStart)/a)+1,this.animator=new c(this.texture,rows,numFrames/rows,numFrames,80,repeatAt),this.material.map=this.texture},g.prototype.tick=function(a,b,c){this.mesh.lookAt(a),this.mesh.rotateZ(this.mesh.tiltDirection*Math.PI/2),this.mesh.rotateZ(Math.sin(b+this.mesh.lon/180*Math.PI)*this.mesh.tiltMultiplier*this.mesh.tiltDirection*-1),this.animator&&this.animator.update(c)},g.prototype.remove=function(){this.scene.remove(this.mesh);for(var a=0;a 0.0 && active > 0.0) {"," dt = mod(dt,1500.0);"," }"," float opacity = 1.0 - dt/ 1500.0;"," if (dt == 0.0 || active == 0.0){"," opacity = 0.0;"," }"," vec3 newPos = getPos(myStartLat, myStartLon - ( dt / 50.0));"," vColor = vec4( color, opacity );"," vec4 mvPosition = modelViewMatrix * vec4( newPos, 1.0 );"," gl_PointSize = 2.5 - (dt / 1500.0);"," gl_Position = projectionMatrix * mvPosition;","}"].join("\n"),f=["varying vec4 vColor;","void main()","{"," gl_FragColor = vColor;"," float depth = gl_FragCoord.z / gl_FragCoord.w;"," float fogFactor = smoothstep(1500.0, 1800.0, depth );"," vec3 fogColor = vec3(0.0);"," gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w), fogFactor );","}"].join("\n"),g=function(a,b){var d={smokeCount:5e3,smokePerPin:30,smokePerSecond:20};if(b)for(var g in d)void 0!==b[g]&&(d[g]=b[g]);this.opts=d,this.geometry=new c.Geometry,this.attributes={myStartTime:{type:"f",value:[]},myStartLat:{type:"f",value:[]},myStartLon:{type:"f",value:[]},altitude:{type:"f",value:[]},active:{type:"f",value:[]}},this.uniforms={currentTime:{type:"f",value:0},color:{type:"c",value:new c.Color("#aaa")}};for(var h=new c.ShaderMaterial({uniforms:this.uniforms,attributes:this.attributes,vertexShader:e,fragmentShader:f,transparent:!0}),g=0;gthis.tileDisplayDuration;)if(this.shutDownFlag&&this.currentTile>=e)this.done=!0,this.shutDownCb();else{this.currentDisplayTime-=this.tileDisplayDuration,this.currentTile++,this.currentTile!=e||this.shutDownFlag||(this.currentTile=g);var c=this.currentTile%this.tilesHorizontal;a.offset.x=c/this.tilesHorizontal;var d=Math.floor(this.currentTile/this.tilesHorizontal);a.offset.y=1-d/this.tilesVertical-1/this.tilesVertical}},this.shutDown=function(a){_this.shutDownFlag=!0,_this.shutDownCb=a}};b.exports=d},{three:12}],21:[function(a,b){var c={renderToCanvas:function(a,b,c){var d=document.createElement("canvas");return d.width=a,d.height=b,c(d.getContext("2d")),d},mapPoint:function(a,b,c){c||(c=500);var d=(90-a)*Math.PI/180,e=(180-b)*Math.PI/180,f=c*Math.sin(d)*Math.cos(e),g=c*Math.cos(d),h=c*Math.sin(d)*Math.sin(e);return{x:f,y:g,z:h}},hexToRgb:function(a){var b=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;a=a.replace(b,function(a,b,c,d){return b+b+c+c+d+d});var c=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a);return c?{r:parseInt(c[1],16),g:parseInt(c[2],16),b:parseInt(c[3],16)}:null},createLabel:function(a,b,c,d,e){var f=document.createElement("canvas"),g=f.getContext("2d");g.font=b+"pt "+d;var h=g.measureText(a).width;return f.width=h,f.height=b+10,f.width%2&&f.width++,f.height%2&&f.height++,e&&(f.height+=30),g.font=b+"pt "+d,g.textAlign="center",g.textBaseline="middle",g.strokeStyle="black",g.miterLimit=2,g.lineJoin="circle",g.lineWidth=6,g.strokeText(a,f.width/2,f.height/2),g.lineWidth=2,g.fillStyle=c,g.fillText(a,f.width/2,f.height/2),e&&(g.strokeStyle=e,g.lineWidth=4,g.beginPath(),g.moveTo(0,f.height-10),g.lineTo(f.width-1,f.height-10),g.stroke()),f}};b.exports=c},{}]},{},[1]); \ No newline at end of file +!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g=j;j++){o=p,p=q[j].subdivide(r[j],j,l);for(var s=0;j>s;s++){var t=new e(o[s],p[s],p[s+1]);m.push(t),s>0&&(t=new e(o[s-1],o[s],p[s]),m.push(t))}}k=m;var u={};for(var v in i){var w=i[v].project(a);u[w]=w}i=u,this.tiles=[];for(var v in i)this.tiles.push(new d(i[v],c))};b.exports=g},{"./face":2,"./point":4,"./tile":5}],4:[function(a,b,c){var d=function(a,b,c){void 0!==a&&void 0!==b&&void 0!==c&&(this.x=a,this.y=b,this.z=c),this.faces=[]};d.prototype.subdivide=function(a,b,c){var e=[];e.push(this);for(var f=1;b>f;f++){var g=new d(this.x*(1-f/b)+a.x*(f/b),this.y*(1-f/b)+a.y*(f/b),this.z*(1-f/b)+a.z*(f/b));g=c(g),e.push(g)}return e.push(a),e},d.prototype.segment=function(a,b){var c=new d;return b=Math.max(.01,Math.min(1,b)),c.x=a.x*(1-b)+this.x*b,c.y=a.y*(1-b)+this.y*b,c.z=a.z*(1-b)+this.z*b,c},d.prototype.midpoint=function(a,b){return this.segment(a,.5)},d.prototype.project=function(a,b){void 0==b&&(b=1),b=Math.max(0,Math.min(1,b));var c=(this.y/this.x,this.z/this.x,this.z/this.y,Math.sqrt(Math.pow(this.x,2)+Math.pow(this.y,2)+Math.pow(this.z,2))),d=a/c;return this.x=this.x*d*b,this.y=this.y*d*b,this.z=this.z*d*b,this},d.prototype.registerFace=function(a){this.faces.push(a)},d.prototype.getOrderedFaces=function(){for(var a=this.faces.slice(),b=[],c=0;ca?360+a:a}function d(a){return a>>>0}function e(a){return a.replace(/^\s+/,"").replace(/\s+$/,"").toLowerCase()}function f(a,b){return Array.prototype.slice.call(a,b)}function g(a,b,c){return a>b?c>a?a:c:b}function h(a,b,c){return(1-c)*a+c*b}function i(a){return a=Math.round(255*a),a>0?255>a?255&a:255:0}function j(a){return a/255}function k(a,b,c){var d,e,f=Math.max(a,b,c),g=Math.min(a,b,c),h=(f+g)/2;if(f==g)d=e=0;else{var i=f-g;switch(e=h>.5?i/(2-f-g):i/(f+g),f){case a:d=(b-c)/i+(c>b?6:0);break;case b:d=(c-a)/i+2;break;case c:d=(a-b)/i+4}d/=6}return[d,e,h]}function l(a,b,c){function d(a,b,c){return 0>c&&(c+=1),c>1&&(c-=1),1/6>c?a+6*(b-a)*c:.5>c?b:2/3>c?a+(b-a)*(2/3-c)*6:a}var e,f,g;if(0==b)e=f=g=c;else{var h=.5>c?c*(1+b):c+b-c*b,i=2*c-h;e=d(i,h,a+1/3),f=d(i,h,a),g=d(i,h,a-1/3)}return[e,f,g]}function m(a){for(var b=[parseInt(a.substr(1,1),16),parseInt(a.substr(2,1),16),parseInt(a.substr(3,1),16),1],c=0;3>c;++c)b[c]=(16*b[c]+b[c])/255;return b}function n(a){return[parseInt(a.substr(1,2),16)/255,parseInt(a.substr(3,2),16)/255,parseInt(a.substr(5,2),16)/255,1]}function o(a){var b,c,d=a[0],e=a[1],f=a[2],g=Math.min(Math.min(d,e),f),h=Math.max(Math.max(d,e),f),i=h;return h==g?c=0:h==d?c=60*((e-f)/(h-g))%360:h==e?c=60*((f-d)/(h-g))+120:h==f&&(c=60*((d-e)/(h-g))+240),0>c&&(c+=360),b=0==h?0:1-g/h,[Math.round(c),Math.round(100*b),Math.round(100*i),a[3]]}function p(b){var c=a(b[0]),d=b[1],e=b[2],d=d/100,e=e/100,f=Math.floor(c/60%6),g=c/60-f,h=e*(1-d),i=e*(1-g*d),j=e*(1-(1-g)*d),k=[];switch(f){case 0:k=[e,j,h];break;case 1:k=[i,e,h];break;case 2:k=[h,e,j];break;case 3:k=[h,i,e];break;case 4:k=[j,h,e];break;case 5:k=[e,h,i]}return[k[0],k[1],k[2],b[3]]}function q(b){var c=k(b[0],b[1],b[2]);return c[0]=a(Math.floor(360*c[0])),c[1]=Math.floor(100*c[1]),c[2]=Math.floor(100*c[2]),c}function r(a){var b=q(a);return b.push(a[3]),b}function s(a){var b=parseFloat(a[0])/360,c=parseFloat(a[1])/100,d=parseFloat(a[2])/100,e=l(b,c,d);return[e[0],e[1],e[2],parseFloat(a[3])]}function t(a){this._value=a}function u(a,b){if(void 0==b)return i(this._value[a]);var c=f(this._value,0);if("string"!=typeof b){var d=this.clone();return d._value[a]=b,d}var e;if(e=b.match(/^([+\-\\*]=?)([0-9.]+)/)){var g=e[1],h=parseFloat(e[2]);switch(g[0]){case"+":c[a]+=h/255;break;case"-":c[a]-=h/255;break;case"*":c[a]*=h}return"="==g[1]?(this._value=c,this):new t(c)}}function v(b){return function(){function c(c,d,e){e=parseFloat(e);var f=o(c._value),g=0;switch(d){case"=":f[b]=e,g=1;break;case"+":f[b]+=e,g=1;break;case"+=":f[b]+=e;break;case"-":f[b]-=e,g=1;break;case"-=":f[b]-=e;break;case"*":f[b]*=e,g=1;break;case"*=":f[b]*=e;break;default:throw"Bad op "+d}return 0==b?f[b]=a(f[b]):1!=b&&2!=b||(f[b]<0?f[b]=0:f[b]>99&&(f[b]=99)),g&&(c=c.clone()),c._value=p(f),c}if(0==arguments.length)return o(this._value)[b];if(1==arguments.length){var d;return"string"==typeof arguments[0]&&(d=arguments[0].match(/^([\+\-\*]=?)([0-9.]+)/))?c(this,d[1],d[2]):c(this,"=",arguments[0])}return 2==arguments.length?c(this,arguments[0],arguments[1]):void 0}}var w={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,216],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[216,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},x={byteOrPercent:function(a){var b;return"string"==typeof a&&(b=a.match(/^([0-9]+)%$/))?Math.floor(255*parseFloat(b[1])/100):parseFloat(a)},floatOrPercent:function(a){var b;return"string"==typeof a&&(b=a.match(/^([0-9]+)%$/))?parseFloat(b[1])/100:parseFloat(a)},numberOrPercent:function(a,b){var c;return"string"==typeof a&&(c=a.match(/^([0-9]+)%$/))?parseFloat(c[1])/100*b:parseFloat(a)},rgba:function(a){for(var b=0;3>b;++b)a[b]=j(x.byteOrPercent(a[b]));return a[3]=x.floatOrPercent(a[b]),new t(a)},rgba8:function(a){return new t([j(x.byteOrPercent(a[0])),j(x.byteOrPercent(a[1])),j(x.byteOrPercent(a[2])),j(x.byteOrPercent(a[3]))])},float3:function(a){for(var b=0;3>b;++b)a[b]=x.floatOrPercent(a[b]);return a[3]=1,new t(a)},float4:function(a){for(var b=0;3>b;++b)a[b]=x.floatOrPercent(a[b]);return a[3]=x.floatOrPercent(a[b]),new t(a)},hsla:function(a){return a[0]=x.numberOrPercent(a[0],360),a[1]=x.numberOrPercent(a[1],100),a[2]=x.numberOrPercent(a[2],100),a[3]=x.numberOrPercent(a[3],1),new t(s(a))},hsva:function(b){return b[0]=a(parseFloat(b[0])),b[1]=Math.max(0,Math.min(100,parseFloat(b[1]))),b[2]=Math.max(0,Math.min(100,parseFloat(b[2]))),b[3]=x.floatOrPercent(b[3]),new t(p(b))}},y={keyword:{},hex3:{},hex7:{},rgb:{parse:function(a){return a=a.slice(0),a.push(1),x.rgba(a)}},rgba:{parse:x.rgba},hsl:{parse:function(a){return a=a.slice(0),a.push(1),x.hsla(a)}},hsla:{parse:x.hsla},hsv:{parse:function(a){return a=a.slice(0),a.push(1),x.hsva(a)}},hsva:{parse:x.hsva},rgb8:{parse:function(a){return a=a.slice(0),a.push(1),x.rgba(a)}},rgba8:{parse:function(a){return x.rgba8(a)}},packed_rgba:{parse:function(a){return a=[a>>24&255,a>>16&255,a>>8&255,(255&a)/255],x.rgba(a)},output:function(a){return d(i(a[0])<<24|i(a[1])<<16|i(a[2])<<8|i(a[3]))}},packed_argb:{parse:function(a){return a=[a>>16&255,a>>8&255,a>>0&255,(a>>24&255)/255],x.rgba(a)},output:function(a){return d(i(a[3])<<24|i(a[0])<<16|i(a[1])<<8|i(a[2]))}},float3:{parse:x.float3},float4:{parse:x.float4}},z=function(){var a=null;if(arguments[0]instanceof t)return new t(arguments[0]._value);if("string"==typeof arguments[0]){var b=arguments[0][0];if("#"==b){if(a=arguments[0].match(/^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/i))return new t(m(a[0]));if(a=arguments[0].match(/^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/i))return new t(n(a[0]))}else{if(a=y[arguments[0].toLowerCase()])return 2==arguments.length?a.parse(arguments[1]):a.parse(f(arguments,1));if(a=arguments[0].match(/^\s*([A-Z][A-Z0-9_]+)\s*\(\s*([\-0-9A-FX]+)\s*\)\s*$/i)){var c=y[a[1].toLowerCase()];return c.parse(a[2])}if(a=arguments[0].match(/^\s*([A-Z][A-Z0-9]+)\s*\(\s*([0-9\.]+%?)\s*,\s*([0-9\.]+%?)\s*,\s*([0-9\.]+%?)\s*(,\s*([0-9\.]+%?)\s*)?\)\s*$/i)){var c=y[a[1].toLowerCase()];if(void 0===a[5]){var d=[a[2],a[3],a[4]];return c.parse(d)}var d=[a[2],a[3],a[4],a[6]];return c.parse(d)}if(1==arguments.length&&(a=w[e(arguments[0])])){var d=a;return new t([j(d[0]),j(d[1]),j(d[2]),1])}}}throw"Could not parse color '"+arguments[0]+"'"},A={white:z("white"),black:z("black"),gray:z("gray")},B={clone:function(){return new t(this._value.slice(0))},html:function(){var a=this,b=this._value,c={hex3:function(){return a.hex3()},hex6:function(){return a.hex6()},rgb:function(){return"rgb("+a.rgb().join(",")+")"},rgba:function(){return"rgba("+a.rgba().join(",")+")"},hsl:function(){return"hsl("+q(b).join(",")+")"},hsla:function(){return"hsla("+r(b).join(",")+")"},keyword:function(){var a,c=195076;for(C in w){for(var d=w[C],e=0,f=0;3>f;++f){var g=b[f]-j(d[f]);e+=g*g}c>e&&(a=C,c=e)}return a}},d=arguments[0]||"rgba";return c[d]()},red:function(){return u.call(this,0,arguments[0])},green:function(){return u.call(this,1,arguments[0])},blue:function(){return u.call(this,2,arguments[0])},alpha:function(){return 1==arguments.length?(c=this.clone(),c._value[3]=x.floatOrPercent(arguments[0]),c):this._value[3]},alpha8:function(){return 1==arguments.length?(c=this.clone(),c._value[3]=x.byteOrPercent(arguments[0])/255,c):Math.floor(255*this._value[3])},grayvalue:function(){var a=this._value;return(a[0]+a[1]+a[2])/3},grayvalue8:function(){return i(this.grayvalue())},luminance:function(){var a=this._value;return.2126*a[0]+.7152*a[1]+.0722*a[2]},luminance8:function(){return i(this.luminance())},hsv:function(){return o(this._value).slice(0,3)},hsva:function(){return o(this._value)},packed_rgba:function(){return y.packed_rgba.output(this._value)},packed_argb:function(){return y.packed_argb.output(this._value)},hue:v(0),saturation:v(1),value:v(2),clamp:function(){var a=this._value;return new t([g(a[0],0,1),g(a[1],0,1),g(a[2],0,1),g(a[3],0,1)])},blend:function(a,b){"number"!=typeof b&&(b=x.floatOrPercent(b));var c=this,d=z(a);return new t([h(c._value[0],d._value[0],b),h(c._value[1],d._value[1],b),h(c._value[2],d._value[2],b),h(c._value[3],d._value[3],b)])},add:function(a){var b=this._value,c=z(a)._value;return new t([b[0]+c[0]*c[3],b[1]+c[1]*c[3],b[2]+c[2]*c[3],b[3]])},inc:function(a){var b=this._value,c=z(a)._value;return b[0]+=c[0]*c[3],b[1]+=c[1]*c[3],b[2]+=c[2]*c[3],this},dec:function(a){var b=this._value,c=z(a)._value;return b[0]-=c[0]*c[3],b[1]-=c[1]*c[3],b[2]-=c[2]*c[3],this},subtract:function(a){var b=this._value,c=z(a)._value;return new t([b[0]-c[0]*c[3],b[1]-c[1]*c[3],b[2]-c[2]*c[3],b[3]])},multiply:function(a){var b=this._value,c=z(a)._value;return new t([b[0]*c[0],b[1]*c[1],b[2]*c[2],b[3]*c[3]])},scale:function(a){var b=this._value;return new t([b[0]*a,b[1]*a,b[2]*a,b[3]])},xor:function(a){var b=this.rgba8(),c=z(a).rgba8();return z("rgba8",b[0]^c[0],b[1]^c[1],b[2]^c[2],b[3])},tint:function(a){return this.blend(A.white,a)},shade:function(a){return this.blend(A.black,a)},tone:function(a){return this.blend(A.gray,a)},complement:function(){var b=this.hsva();return b[0]=a(b[0]+180),new t(p(b))},triad:function(){return[new t(this._value),this.hue("+120"),this.hue("+240")]},hueSet:function(){for(var a=0,b=[],c=100;c>=30;c-=35)for(var d=100;d>=30;d-=35)b.push(this.hue("+",a).saturation(c).value(d));return b},hueRange:function(a,b){for(var c=this.hue(),d=[],e=0;b>e;++e){var f=c+2*(e/(b-1)-.5)*a;d.push(this.hue("=",f))}return d},contrastWhiteBlack:function(){return z(this.value()<50?"white":"black")},contrastGray:function(){var a=this.hsva(),b=a[2]<30?a[2]+20:a[2]-20;return new t(p([a[0],0,b,a[3]]))},hex3:function(){function a(a,b){return Math.min(Math.round(i(a)/16),15).toString(16)}return"#"+a(this._value[0])+a(this._value[1])+a(this._value[2])},hex6:function(){function a(a,b){var c=i(a).toString(16);return c.length<2?"0"+c:c}return"#"+a(this._value[0])+a(this._value[1])+a(this._value[2])},rgb:function(){var a=this._value;return[i(a[0]),i(a[1]),i(a[2])]},rgba:function(){var a=this._value;return[i(a[0]),i(a[1]),i(a[2]),a[3]]},rgb8:function(){var a=this._value;return[i(a[0]),i(a[1]),i(a[2])]},rgba8:function(){var a=this._value;return[i(a[0]),i(a[1]),i(a[2]),this.alpha8()]},float3:function(){return[this._value[0],this._value[1],this._value[2]]},float4:function(){return[this._value[0],this._value[1],this._value[2],this._value[3]]}};B.sub=B.subtract,B.mul=B.multiply;for(var C in B)t.prototype[C]=B[C];z.float3=function(a,b,c){return new t([a,b,c,1])},z.float4=function(a,b,c,d){return new t([a,b,c,d])},z.version="0.2.4",z.Color=t,"undefined"!=typeof b&&b.exports?b.exports=z:"undefined"!=typeof window&&(window.pusher=window.pusher||{},window.pusher.color=z)}()},{}],7:[function(a,b,c){!function d(a,c,e){function f(a,b){return this instanceof f?(g(a)?(b=a[1],a=a[0]):"object"==typeof a&&a&&(b=a.y,a=a.x),this.x=f.clean(a||0),void(this.y=f.clean(b||0))):new f(a,b)}var g=function(a){return"[object Array]"===Object.prototype.toString.call(a)};f.prototype={change:function(a){if(a)this.observers?this.observers.push(a):this.observers=[a];else if(this.observers)for(var b=this.observers.length-1;b>=0;b--)this.observers[b](this);return this},ignore:function(a){if(this.observers)for(var b=this.observers,c=b.length;c--;)b[c]===a&&b.splice(c,1);return this},set:function(a,b,c){return"number"!=typeof a&&(c=b,b=a.y,a=a.x),this.x===a&&this.y===b?this:(this.x=f.clean(a),this.y=f.clean(b),c!==!1?this.change():void 0)},zero:function(){return this.set(0,0)},clone:function(){return new this.constructor(this.x,this.y)},negate:function(a){return a?new this.constructor(-this.x,-this.y):this.set(-this.x,-this.y)},add:function(a,b){return b?new this.constructor(this.x+a.x,this.y+a.y):(this.x+=a.x,this.y+=a.y,this.change())},subtract:function(a,b){return b?new this.constructor(this.x-a.x,this.y-a.y):(this.x-=a.x,this.y-=a.y,this.change())},multiply:function(a,b){var c,d;return"number"!=typeof a?(c=a.x,d=a.y):c=d=a,b?new this.constructor(this.x*c,this.y*d):this.set(this.x*c,this.y*d)},rotate:function(a,b,c){var d,e,f=this.x,g=this.y,h=Math.cos(a),i=Math.sin(a);return b=b?-1:1,d=h*f-b*i*g,e=b*i*f+h*g,c?new this.constructor(d,e):this.set(d,e)},length:function(){var a=this.x,b=this.y;return Math.sqrt(a*a+b*b)},lengthSquared:function(){var a=this.x,b=this.y;return a*a+b*b},distance:function(a){var b=this.x-a.x,c=this.y-a.y;return Math.sqrt(b*b+c*c)},normalize:function(a){var b=this.length(),c=bc?c:e,h=f>d?d:f;return b?new this.constructor(g,h):this.set(g,h)},max:function(a,b){var c=this.x,d=this.y,e=a.x,f=a.y,g=c>e?c:e,h=d>f?d:f;return b?new this.constructor(g,h):this.set(g,h)},clamp:function(a,b,c){var d=this.min(b,!0).max(a);return c?d:this.set(d.x,d.y)},lerp:function(a,b){return this.add(a.subtract(this,!0).multiply(b),!0)},skew:function(){return new this.constructor(-this.y,this.x)},dot:function(a){return f.clean(this.x*a.x+a.y*this.y)},perpDot:function(a){return f.clean(this.x*a.y-this.y*a.x)},angleTo:function(a){return Math.atan2(this.perpDot(a),this.dot(a))},divide:function(a,b){var c,d;if("number"!=typeof a?(c=a.x,d=a.y):c=d=a,0===c||0===d)throw new Error("division by zero");if(isNaN(c)||isNaN(d))throw new Error("NaN detected");return b?new this.constructor(this.x/c,this.y/d):this.set(this.x/c,this.y/d)},isPointOnLine:function(a,b){return(a.y-this.y)*(a.x-b.x)===(a.y-b.y)*(a.x-this.x)},toArray:function(){return[this.x,this.y]},fromArray:function(a){return this.set(a[0],a[1])},toJSON:function(){return{x:this.x,y:this.y}},toString:function(){return"("+this.x+", "+this.y+")"},constructor:f},f.fromArray=function(a,b){return new(b||f)(a[0],a[1])},f.precision=c||8;var h=Math.pow(10,f.precision);return f.clean=a||function(a){if(isNaN(a))throw new Error("NaN detected");if(!isFinite(a))throw new Error("Infinity detected");return Math.round(a)===a?a:Math.round(a*h)/h},f.inject=d,a||(f.fast=d(function(a){return a}),"undefined"!=typeof b&&"object"==typeof b.exports?b.exports=f:window.Vec2=window.Vec2||f),f}()},{}],8:[function(a,b,c){var d,e=a("vec2"),f=a("./quadtree2helper"),g=a("./quadtree2validator"),h=a("./quadtree2quadrant");d=function(a,b,c){var d,i={objects_:{},quadrants_:{},ids_:1,quadrantIds_:1,autoId_:!0,inited_:!1,debug_:!1,size_:void 0,root_:void 0,quadrantObjectsLimit_:void 0,quadrantLevelLimit_:void 0,quadrantSizeLimit_:void 0},j=new g,k={p:"pos_",r:"rad_",id:"id_"},l={data:{necessary:{size_:j.isVec2,quadrantObjectsLimit_:j.isNumber,quadrantLevelLimit_:j.isNumber}},k:{necessary:{p:j.isVec2},c:{necessary:{r:j.isNumber}}}},m={nextId:function(){return i.ids_++},nextQuadrantId:function(a){var b=i.quadrantIds_;return i.quadrantIds_+=a||4,b},hasCollision:function(a,b){return a[k.r]+b[k.r]>a[k.p].distance(b[k.p])},removeQuadrantParentQuadrants:function(a,b){a.parent_&&b[a.parent_.id_]&&(delete b[a.parent_.id_],m.removeQuadrantParentQuadrants(a.parent_,b))},getSubtreeTopQuadrant:function p(a,b){return a.parent_&&b[a.parent_.id_]?p(a.parent_,b):a},removeQuadrantChildtree:function(a,b){var c,d=a.getChildren();for(c=0;ci.quadrantObjectsLimit_)){for(a.refactoring_=!0,b=0;b0?!1:(this.children_.push(new d(this.leftTop_,this.rad_,a++,this),new d(this.topMid_,this.rad_,a++,this),new d(this.leftMid_,this.rad_,a++,this),new d(this.center_,this.rad_,a++,this)),a)},looseChildren:function(){this.children_=[]},addObjects:function(a){var b;for(b in a)this.addObject(b,a[b])},addObject:function(a,b){this.objectCount_++,this.objects_[a]=b},removeObjects:function(a,b){var c;a||(a=[]);for(c in this.objects_)a.push({obj:this.objects_[c],quadrant:this}),delete this.objects_[c];return this.objectCount_=0,b&&1!==b||this.parent_&&this.parent_.removeObjects(a,1),b&&-1!==b||this.children_.forEach(function(b){b.removeObjects(a,-1)}),a},removeObject:function(a){var b=this.objects_[a];return this.objectCount_--,delete this.objects_[a],b},getObjectCountForLimit:function(){var a,b,c={};for(b in this.objects_)c[b]=!0;for(a=0;athis.rad_.x+b?!1:c.y>this.rad_.y+b?!1:c.x<=this.rad_.x?!0:c.y<=this.rad_.y?!0:(cornerDistSq=Math.pow(c.x-this.rad_.x,2)+Math.pow(c.y-this.rad_.y,2),cornerDistSq<=Math.pow(b,2))},hasChildren:function(){return 0!==this.getChildCount()},getChildCount:function(a){var b=this.children_.length;return a&&this.children_.forEach(function(c){b+=c.getChildCount(a)}),b},getChildren:function(a,b){return b||(b=[]),b.push.apply(b,this.children_),a&&this.children_.forEach(function(c){c.getChildren(a,b)}),b},getObjectsUp:function(a){var b;if(!a.quadrants[this.id_]){a.quadrants[this.id_]=!0;for(b in this.objects_)a.objects[b]=this.objects_[b];this.parent_&&this.parent_.getObjectsUp(a)}},getObjectsDown:function(a){var b;if(!a.quadrants[this.id_]){a.quadrants[this.id_]=!0;for(b in this.objects_)a.objects[b]=this.objects_[b];for(b=0;b>16&255)/255,this.g=(a>>8&255)/255,this.b=(255&a)/255,this},setRGB:function(a,b,c){return this.r=a,this.g=b,this.b=c,this},setHSL:function(a,b,c){if(0===b)this.r=this.g=this.b=c;else{var d=function(a,b,c){return 0>c&&(c+=1),c>1&&(c-=1),1/6>c?a+6*(b-a)*c:.5>c?b:2/3>c?a+6*(b-a)*(2/3-c):a},e=.5>=c?c*(1+b):c+b-c*b,f=2*c-e;this.r=d(f,e,a+1/3),this.g=d(f,e,a),this.b=d(f,e,a-1/3)}return this},setStyle:function(a){if(/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test(a)){var b=/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec(a);return this.r=Math.min(255,parseInt(b[1],10))/255,this.g=Math.min(255,parseInt(b[2],10))/255,this.b=Math.min(255,parseInt(b[3],10))/255,this}if(/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test(a)){var b=/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec(a);return this.r=Math.min(100,parseInt(b[1],10))/100,this.g=Math.min(100,parseInt(b[2],10))/100,this.b=Math.min(100,parseInt(b[3],10))/100,this}if(/^\#([0-9a-f]{6})$/i.test(a)){var b=/^\#([0-9a-f]{6})$/i.exec(a);return this.setHex(parseInt(b[1],16)),this}if(/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(a)){var b=/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(a);return this.setHex(parseInt(b[1]+b[1]+b[2]+b[2]+b[3]+b[3],16)),this}return/^(\w+)$/i.test(a)?(this.setHex(e.ColorKeywords[a]),this):void 0},copy:function(a){return this.r=a.r,this.g=a.g,this.b=a.b,this},copyGammaToLinear:function(a){return this.r=a.r*a.r,this.g=a.g*a.g,this.b=a.b*a.b,this},copyLinearToGamma:function(a){return this.r=Math.sqrt(a.r),this.g=Math.sqrt(a.g),this.b=Math.sqrt(a.b),this},convertGammaToLinear:function(){var a=this.r,b=this.g,c=this.b;return this.r=a*a,this.g=b*b,this.b=c*c,this},convertLinearToGamma:function(){return this.r=Math.sqrt(this.r),this.g=Math.sqrt(this.g),this.b=Math.sqrt(this.b),this},getHex:function(){return 255*this.r<<16^255*this.g<<8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(a){var b,c,d=a||{h:0,s:0,l:0},e=this.r,f=this.g,g=this.b,h=Math.max(e,f,g),i=Math.min(e,f,g),j=(i+h)/2;if(i===h)b=0,c=0;else{var k=h-i;switch(c=.5>=j?k/(h+i):k/(2-h-i),h){case e:b=(f-g)/k+(g>f?6:0);break;case f:b=(g-e)/k+2;break;case g:b=(e-f)/k+4}b/=6}return d.h=b,d.s=c,d.l=j,d},getStyle:function(){return"rgb("+(255*this.r|0)+","+(255*this.g|0)+","+(255*this.b|0)+")"},offsetHSL:function(a,b,c){var d=this.getHSL();return d.h+=a,d.s+=b,d.l+=c,this.setHSL(d.h,d.s,d.l),this},add:function(a){return this.r+=a.r,this.g+=a.g,this.b+=a.b,this},addColors:function(a,b){return this.r=a.r+b.r,this.g=a.g+b.g,this.b=a.b+b.b,this},addScalar:function(a){return this.r+=a,this.g+=a,this.b+=a,this},multiply:function(a){return this.r*=a.r,this.g*=a.g,this.b*=a.b,this},multiplyScalar:function(a){return this.r*=a,this.g*=a,this.b*=a,this},lerp:function(a,b){return this.r+=(a.r-this.r)*b,this.g+=(a.g-this.g)*b,this.b+=(a.b-this.b)*b,this},equals:function(a){return a.r===this.r&&a.g===this.g&&a.b===this.b},fromArray:function(a){return this.r=a[0],this.g=a[1],this.b=a[2],this},toArray:function(){return[this.r,this.g,this.b]},clone:function(){return(new e.Color).setRGB(this.r,this.g,this.b)}},e.ColorKeywords={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},e.Quaternion=function(a,b,c,d){this._x=a||0,this._y=b||0,this._z=c||0,this._w=void 0!==d?d:1},e.Quaternion.prototype={constructor:e.Quaternion,_x:0,_y:0,_z:0,_w:0,_euler:void 0,_updateEuler:function(a){void 0!==this._euler&&this._euler.setFromQuaternion(this,void 0,!1)},get x(){return this._x},set x(a){this._x=a,this._updateEuler()},get y(){return this._y},set y(a){this._y=a,this._updateEuler()},get z(){return this._z},set z(a){this._z=a,this._updateEuler()},get w(){return this._w},set w(a){this._w=a,this._updateEuler()},set:function(a,b,c,d){return this._x=a,this._y=b,this._z=c,this._w=d,this._updateEuler(),this},copy:function(a){return this._x=a._x,this._y=a._y,this._z=a._z,this._w=a._w,this._updateEuler(),this},setFromEuler:function(a,b){if(!(a instanceof e.Euler))return e.onerror("expecting a Euler",a);var c=Math.cos(a._x/2),d=Math.cos(a._y/2),f=Math.cos(a._z/2),g=Math.sin(a._x/2),h=Math.sin(a._y/2),i=Math.sin(a._z/2);return"XYZ"===a.order?(this._x=g*d*f+c*h*i,this._y=c*h*f-g*d*i,this._z=c*d*i+g*h*f,this._w=c*d*f-g*h*i):"YXZ"===a.order?(this._x=g*d*f+c*h*i,this._y=c*h*f-g*d*i,this._z=c*d*i-g*h*f,this._w=c*d*f+g*h*i):"ZXY"===a.order?(this._x=g*d*f-c*h*i,this._y=c*h*f+g*d*i,this._z=c*d*i+g*h*f,this._w=c*d*f-g*h*i):"ZYX"===a.order?(this._x=g*d*f-c*h*i,this._y=c*h*f+g*d*i,this._z=c*d*i-g*h*f,this._w=c*d*f+g*h*i):"YZX"===a.order?(this._x=g*d*f+c*h*i,this._y=c*h*f+g*d*i,this._z=c*d*i-g*h*f,this._w=c*d*f-g*h*i):"XZY"===a.order&&(this._x=g*d*f-c*h*i,this._y=c*h*f-g*d*i,this._z=c*d*i+g*h*f,this._w=c*d*f+g*h*i),b!==!1&&this._updateEuler(),this},setFromAxisAngle:function(a,b){var c=b/2,d=Math.sin(c);return this._x=a.x*d,this._y=a.y*d,this._z=a.z*d,this._w=Math.cos(c),this._updateEuler(),this},setFromRotationMatrix:function(a){var b,c=a.elements,d=c[0],e=c[4],f=c[8],g=c[1],h=c[5],i=c[9],j=c[2],k=c[6],l=c[10],m=d+h+l;return m>0?(b=.5/Math.sqrt(m+1),this._w=.25/b,this._x=(k-i)*b,this._y=(f-j)*b,this._z=(g-e)*b):d>h&&d>l?(b=2*Math.sqrt(1+d-h-l),this._w=(k-i)/b,this._x=.25*b,this._y=(e+g)/b,this._z=(f+j)/b):h>l?(b=2*Math.sqrt(1+h-d-l),this._w=(f-j)/b,this._x=(e+g)/b,this._y=.25*b,this._z=(i+k)/b):(b=2*Math.sqrt(1+l-d-h),this._w=(g-e)/b,this._x=(f+j)/b,this._y=(i+k)/b,this._z=.25*b),this._updateEuler(),this},inverse:function(){return this.conjugate().normalize(),this},add:function(a){return this._x+=a._x,this._y+=a._y,this._z+=a._z,this._w+=a._w,this},sub:function(a){return this._x-=a._x,this._y-=a._y,this._z-=a._z,this._w-=a._w,this},multiplyScalar:function(a){return this._x*=a,this._y*=a,this._z*=a,this._w*=a,this},conjugate:function(){return this._x*=-1,this._y*=-1,this._z*=-1,this._updateEuler(),this},lengthSq:function(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w},length:function(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)},normalize:function(){var a=this.length();return 0===a?(this._x=0,this._y=0,this._z=0,this._w=1):(a=1/a,this._x=this._x*a,this._y=this._y*a,this._z=this._z*a,this._w=this._w*a),this},multiply:function(a,b){return void 0!==b?(e.onwarning("DEPRECATED: Quaternion's .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z,f=a._w,g=b._x,h=b._y,i=b._z,j=b._w;return this._x=c*j+f*g+d*i-e*h,this._y=d*j+f*h+e*g-c*i,this._z=e*j+f*i+c*h-d*g,this._w=f*j-c*g-d*h-e*i,this._updateEuler(),this},multiplyVector3:function(a){return e.onwarning("DEPRECATED: Quaternion's .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead."),a.applyQuaternion(this)},slerp:function(a,b){var c=this._x,d=this._y,e=this._z,f=this._w,g=f*a._w+c*a._x+d*a._y+e*a._z;if(0>g?(this._w=-a._w,this._x=-a._x,this._y=-a._y,this._z=-a._z,g=-g):this.copy(a),g>=1)return this._w=f,this._x=c,this._y=d,this._z=e,this;var h=Math.acos(g),i=Math.sqrt(1-g*g);if(Math.abs(i)<.001)return this._w=.5*(f+this._w),this._x=.5*(c+this._x),this._y=.5*(d+this._y),this._z=.5*(e+this._z),this;var j=Math.sin((1-b)*h)/i,k=Math.sin(b*h)/i;return this._w=f*j+this._w*k,this._x=c*j+this._x*k,this._y=d*j+this._y*k,this._z=e*j+this._z*k,this._updateEuler(),this},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w},fromArray:function(a){return this._x=a[0],this._y=a[1],this._z=a[2],this._w=a[3],this._updateEuler(),this},toArray:function(){return[this._x,this._y,this._z,this._w]},clone:function(){return new e.Quaternion(this._x,this._y,this._z,this._w)}},e.Quaternion.slerp=function(a,b,c,d){return c.copy(a).slerp(b,d)},e.Vector2=function(a,b){this.x=a||0,this.y=b||0},e.Vector2.prototype={constructor:e.Vector2,set:function(a,b){return this.x=a,this.y=b,this},setX:function(a){return this.x=a,this},setY:function(a){return this.y=a,this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:return e.onerror("index is out of range: "+a)}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:return e.onerror("index is out of range: "+a)}},copy:function(a){return this.x=a.x,this.y=a.y,this},add:function(a,b){return void 0!==b?(e.onwarning("DEPRECATED: Vector2's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b)):(this.x+=a.x,this.y+=a.y,this)},addVectors:function(a,b){return this.x=a.x+b.x,this.y=a.y+b.y,this},addScalar:function(a){return this.x+=a,this.y+=a,this},sub:function(a,b){return void 0!==b?(e.onwarning("DEPRECATED: Vector2's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b)):(this.x-=a.x,this.y-=a.y,this)},subVectors:function(a,b){return this.x=a.x-b.x,this.y=a.y-b.y,this},multiplyScalar:function(a){return this.x*=a,this.y*=a,this},divideScalar:function(a){if(0!==a){var b=1/a;this.x*=b,this.y*=b}else this.x=0,this.y=0;return this},min:function(a){return this.x>a.x&&(this.x=a.x),this.y>a.y&&(this.y=a.y),this},max:function(a){return this.xb.x&&(this.x=b.x),this.yb.y&&(this.y=b.y),this},clampScalar:function(){var a,b;return function(c,d){return void 0===a&&(a=new e.Vector2,b=new e.Vector2),a.set(c,c),b.set(d,d),this.clamp(a,b)}}(),floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},roundToZero:function(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y;return b*b+c*c},setLength:function(a){var b=this.length();return 0!==b&&a!==b&&this.multiplyScalar(a/b),this},lerp:function(a,b){return this.x+=(a.x-this.x)*b,this.y+=(a.y-this.y)*b,this},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a){return this.x=a[0],this.y=a[1],this},toArray:function(){return[this.x,this.y]},clone:function(){return new e.Vector2(this.x,this.y)}},e.Vector3=function(a,b,c){this.x=a||0,this.y=b||0,this.z=c||0},e.Vector3.prototype={constructor:e.Vector3,set:function(a,b,c){return this.x=a,this.y=b,this.z=c,this},setX:function(a){return this.x=a,this},setY:function(a){return this.y=a,this},setZ:function(a){return this.z=a,this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:return e.onerror("index is out of range: "+a)}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:return e.onerror("index is out of range: "+a)}},copy:function(a){return this.x=a.x,this.y=a.y,this.z=a.z,this},add:function(a,b){return void 0!==b?(e.onwarning("DEPRECATED: Vector3's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b)):(this.x+=a.x,this.y+=a.y,this.z+=a.z,this)},addScalar:function(a){return this.x+=a,this.y+=a,this.z+=a,this},addVectors:function(a,b){return this.x=a.x+b.x,this.y=a.y+b.y,this.z=a.z+b.z,this},sub:function(a,b){return void 0!==b?(e.onwarningn("DEPRECATED: Vector3's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b)):(this.x-=a.x,this.y-=a.y,this.z-=a.z,this)},subVectors:function(a,b){return this.x=a.x-b.x,this.y=a.y-b.y,this.z=a.z-b.z,this},multiply:function(a,b){return void 0!==b?(e.onwarning("DEPRECATED: Vector3's .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(a,b)):(this.x*=a.x,this.y*=a.y,this.z*=a.z,this)},multiplyScalar:function(a){return this.x*=a,this.y*=a,this.z*=a,this},multiplyVectors:function(a,b){return this.x=a.x*b.x,this.y=a.y*b.y,this.z=a.z*b.z,this},applyEuler:function(){var a;return function(b){return b instanceof e.Euler?(void 0===a&&(a=new e.Quaternion),this.applyQuaternion(a.setFromEuler(b)),this):e.onerror("expecting an Euler",b)}}(),applyAxisAngle:function(){var a;return function(b,c){return void 0===a&&(a=new e.Quaternion),this.applyQuaternion(a.setFromAxisAngle(b,c)),this}}(),applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z,e=a.elements;return this.x=e[0]*b+e[3]*c+e[6]*d,this.y=e[1]*b+e[4]*c+e[7]*d,this.z=e[2]*b+e[5]*c+e[8]*d,this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=a.elements;return this.x=e[0]*b+e[4]*c+e[8]*d+e[12],this.y=e[1]*b+e[5]*c+e[9]*d+e[13],this.z=e[2]*b+e[6]*c+e[10]*d+e[14],this},applyProjection:function(a){var b=this.x,c=this.y,d=this.z,e=a.elements,f=1/(e[3]*b+e[7]*c+e[11]*d+e[15]);return this.x=(e[0]*b+e[4]*c+e[8]*d+e[12])*f,this.y=(e[1]*b+e[5]*c+e[9]*d+e[13])*f,this.z=(e[2]*b+e[6]*c+e[10]*d+e[14])*f,this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,g=a.z,h=a.w,i=h*b+f*d-g*c,j=h*c+g*b-e*d,k=h*d+e*c-f*b,l=-e*b-f*c-g*d;return this.x=i*h+l*-e+j*-g-k*-f,this.y=j*h+l*-f+k*-e-i*-g,this.z=k*h+l*-g+i*-f-j*-e,this},transformDirection:function(a){var b=this.x,c=this.y,d=this.z,e=a.elements;return this.x=e[0]*b+e[4]*c+e[8]*d,this.y=e[1]*b+e[5]*c+e[9]*d,this.z=e[2]*b+e[6]*c+e[10]*d,this.normalize(),this},divide:function(a){return this.x/=a.x,this.y/=a.y,this.z/=a.z,this},divideScalar:function(a){if(0!==a){var b=1/a;this.x*=b,this.y*=b,this.z*=b}else this.x=0,this.y=0,this.z=0;return this},min:function(a){return this.x>a.x&&(this.x=a.x),this.y>a.y&&(this.y=a.y),this.z>a.z&&(this.z=a.z),this},max:function(a){return this.xb.x&&(this.x=b.x),this.yb.y&&(this.y=b.y),this.zb.z&&(this.z=b.z),this},clampScalar:function(){var a,b;return function(c,d){return void 0===a&&(a=new e.Vector3,b=new e.Vector3),a.set(c,c,c),b.set(d,d,d),this.clamp(a,b)}}(),floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this},roundToZero:function(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this.z=this.z<0?Math.ceil(this.z):Math.floor(this.z),this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){var b=this.length();return 0!==b&&a!==b&&this.multiplyScalar(a/b),this},lerp:function(a,b){return this.x+=(a.x-this.x)*b,this.y+=(a.y-this.y)*b,this.z+=(a.z-this.z)*b,this},cross:function(a,b){if(void 0!==b)return e.onwarning("DEPRECATED: Vector3's .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b);var c=this.x,d=this.y,f=this.z;return this.x=d*a.z-f*a.y,this.y=f*a.x-c*a.z,this.z=c*a.y-d*a.x,this},crossVectors:function(a,b){var c=a.x,d=a.y,e=a.z,f=b.x,g=b.y,h=b.z;return this.x=d*h-e*g,this.y=e*f-c*h,this.z=c*g-d*f,this},projectOnVector:function(){var a,b;return function(c){return void 0===a&&(a=new e.Vector3),a.copy(c).normalize(),b=this.dot(a),this.copy(a).multiplyScalar(b)}}(),projectOnPlane:function(){var a;return function(b){return void 0===a&&(a=new e.Vector3),a.copy(this).projectOnVector(b),this.sub(a)}}(),reflect:function(){var a;return function(b){return void 0===a&&(a=new e.Vector3),this.sub(a.copy(b).multiplyScalar(2*this.dot(b)))}}(),angleTo:function(a){var b=this.dot(a)/(this.length()*a.length());return Math.acos(e.Math.clamp(b,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y,d=this.z-a.z;return b*b+c*c+d*d},setEulerFromRotationMatrix:function(a,b){e.onerror("REMOVED: Vector3's setEulerFromRotationMatrix has been removed in favor of Euler.setFromRotationMatrix(), please update your code.")},setEulerFromQuaternion:function(a,b){e.onerror("REMOVED: Vector3's setEulerFromQuaternion: has been removed in favor of Euler.setFromQuaternion(), please update your code.")},getPositionFromMatrix:function(a){return e.onwarning("DEPRECATED: Vector3's .getPositionFromMatrix() has been renamed to .setFromMatrixPosition(). Please update your code."),this.setFromMatrixPosition(a)},getScaleFromMatrix:function(a){return e.onwarning("DEPRECATED: Vector3's .getScaleFromMatrix() has been renamed to .setFromMatrixScale(). Please update your code."),this.setFromMatrixScale(a)},getColumnFromMatrix:function(a,b){return e.onwarning("DEPRECATED: Vector3's .getColumnFromMatrix() has been renamed to .setFromMatrixColumn(). Please update your code."),this.setFromMatrixColumn(a,b)},setFromMatrixPosition:function(a){return this.x=a.elements[12],this.y=a.elements[13],this.z=a.elements[14],this},setFromMatrixScale:function(a){var b=this.set(a.elements[0],a.elements[1],a.elements[2]).length(),c=this.set(a.elements[4],a.elements[5],a.elements[6]).length(),d=this.set(a.elements[8],a.elements[9],a.elements[10]).length();return this.x=b,this.y=c,this.z=d,this},setFromMatrixColumn:function(a,b){var c=4*a,d=b.elements;return this.x=d[c],this.y=d[c+1],this.z=d[c+2],this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a){return this.x=a[0],this.y=a[1],this.z=a[2],this},toArray:function(){return[this.x,this.y,this.z]},clone:function(){return new e.Vector3(this.x,this.y,this.z)}},e.Vector4=function(a,b,c,d){this.x=a||0,this.y=b||0,this.z=c||0,this.w=void 0!==d?d:1},e.Vector4.prototype={constructor:e.Vector4,set:function(a,b,c,d){return this.x=a,this.y=b,this.z=c,this.w=d,this},setX:function(a){return this.x=a,this},setY:function(a){return this.y=a,this},setZ:function(a){return this.z=a,this},setW:function(a){return this.w=a,this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:return e.onerror("index is out of range: "+a)}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:return e.onerror("index is out of range: "+a)}},copy:function(a){return this.x=a.x,this.y=a.y,this.z=a.z,this.w=void 0!==a.w?a.w:1,this},add:function(a,b){return void 0!==b?(e.onwarning("DEPRECATED: Vector4's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b)):(this.x+=a.x,this.y+=a.y,this.z+=a.z,this.w+=a.w,this)},addScalar:function(a){return this.x+=a,this.y+=a,this.z+=a,this.w+=a,this},addVectors:function(a,b){return this.x=a.x+b.x,this.y=a.y+b.y,this.z=a.z+b.z,this.w=a.w+b.w,this},sub:function(a,b){return void 0!==b?(e.onwarning("DEPRECATED: Vector4's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b)):(this.x-=a.x,this.y-=a.y,this.z-=a.z,this.w-=a.w,this)},subVectors:function(a,b){return this.x=a.x-b.x,this.y=a.y-b.y,this.z=a.z-b.z,this.w=a.w-b.w,this},multiplyScalar:function(a){return this.x*=a,this.y*=a,this.z*=a,this.w*=a,this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=this.w,f=a.elements;return this.x=f[0]*b+f[4]*c+f[8]*d+f[12]*e,this.y=f[1]*b+f[5]*c+f[9]*d+f[13]*e,this.z=f[2]*b+f[6]*c+f[10]*d+f[14]*e,this.w=f[3]*b+f[7]*c+f[11]*d+f[15]*e,this},divideScalar:function(a){if(0!==a){var b=1/a;this.x*=b,this.y*=b,this.z*=b,this.w*=b}else this.x=0,this.y=0,this.z=0,this.w=1;return this},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);return 1e-4>b?(this.x=1,this.y=0,this.z=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b),this},setAxisAngleFromRotationMatrix:function(a){var b,c,d,e,f=.01,g=.1,h=a.elements,i=h[0],j=h[4],k=h[8],l=h[1],m=h[5],n=h[9],o=h[2],p=h[6],q=h[10];if(Math.abs(j-l)s&&r>t?f>r?(c=0,d=.707106781,e=.707106781):(c=Math.sqrt(r),d=u/c,e=v/c):s>t?f>s?(c=.707106781,d=0,e=.707106781):(d=Math.sqrt(s),c=u/d,e=w/d):f>t?(c=.707106781,d=.707106781,e=0):(e=Math.sqrt(t),c=v/e,d=w/e),this.set(c,d,e,b),this}var x=Math.sqrt((p-n)*(p-n)+(k-o)*(k-o)+(l-j)*(l-j));return Math.abs(x)<.001&&(x=1),this.x=(p-n)/x,this.y=(k-o)/x,this.z=(l-j)/x,this.w=Math.acos((i+m+q-1)/2),this},min:function(a){return this.x>a.x&&(this.x=a.x),this.y>a.y&&(this.y=a.y),this.z>a.z&&(this.z=a.z),this.w>a.w&&(this.w=a.w),this},max:function(a){return this.xb.x&&(this.x=b.x),this.yb.y&&(this.y=b.y),this.zb.z&&(this.z=b.z),this.wb.w&&(this.w=b.w),this},clampScalar:function(){var a,b;return function(c,d){return void 0===a&&(a=new e.Vector4,b=new e.Vector4),a.set(c,c,c,c),b.set(d,d,d,d),this.clamp(a,b)}}(),floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this.w=Math.floor(this.w),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this.w=Math.ceil(this.w),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this.w=Math.round(this.w),this},roundToZero:function(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this.z=this.z<0?Math.ceil(this.z):Math.floor(this.z),this.w=this.w<0?Math.ceil(this.w):Math.floor(this.w),this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){var b=this.length();return 0!==b&&a!==b&&this.multiplyScalar(a/b),this},lerp:function(a,b){return this.x+=(a.x-this.x)*b,this.y+=(a.y-this.y)*b,this.z+=(a.z-this.z)*b,this.w+=(a.w-this.w)*b,this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},fromArray:function(a){return this.x=a[0],this.y=a[1],this.z=a[2],this.w=a[3],this},toArray:function(){return[this.x,this.y,this.z,this.w]},clone:function(){return new e.Vector4(this.x,this.y,this.z,this.w)}},e.Euler=function(a,b,c,d){this._x=a||0,this._y=b||0,this._z=c||0,this._order=d||e.Euler.DefaultOrder},e.Euler.RotationOrders=["XYZ","YZX","ZXY","XZY","YXZ","ZYX"],e.Euler.DefaultOrder="XYZ",e.Euler.prototype={constructor:e.Euler,_x:0,_y:0,_z:0,_order:e.Euler.DefaultOrder,_quaternion:void 0,_updateQuaternion:function(){void 0!==this._quaternion&&this._quaternion.setFromEuler(this,!1)},get x(){return this._x},set x(a){this._x=a,this._updateQuaternion()},get y(){return this._y},set y(a){this._y=a,this._updateQuaternion()},get z(){return this._z},set z(a){this._z=a,this._updateQuaternion()},get order(){return this._order}, +set order(a){this._order=a,this._updateQuaternion()},set:function(a,b,c,d){return this._x=a,this._y=b,this._z=c,this._order=d||this._order,this._updateQuaternion(),this},setFromVector:function(a,b){return this._x=a.x,this._y=a.y,this._z=a.z,this._order=b||this._order,this._updateQuaternion(),this},copy:function(a){return this._x=a._x,this._y=a._y,this._z=a._z,this._order=a._order,this._updateQuaternion(),this},setFromRotationMatrix:function(a,b,c){function d(a){return Math.min(Math.max(a,-1),1)}var f=a.elements,g=f[0],h=f[4],i=f[8],j=f[1],k=f[5],l=f[9],m=f[2],n=f[6],o=f[10];return b=b||this._order,"XYZ"===b?(this._y=Math.asin(d(i)),Math.abs(i)<.99999?(this._x=Math.atan2(-l,o),this._z=Math.atan2(-h,g)):(this._x=Math.atan2(n,k),this._z=0)):"YXZ"===b?(this._x=Math.asin(-d(l)),Math.abs(l)<.99999?(this._y=Math.atan2(i,o),this._z=Math.atan2(j,k)):(this._y=Math.atan2(-m,g),this._z=0)):"ZXY"===b?(this._x=Math.asin(d(n)),Math.abs(n)<.99999?(this._y=Math.atan2(-m,o),this._z=Math.atan2(-h,k)):(this._y=0,this._z=Math.atan2(j,g))):"ZYX"===b?(this._y=Math.asin(-d(m)),Math.abs(m)<.99999?(this._x=Math.atan2(n,o),this._z=Math.atan2(j,g)):(this._x=0,this._z=Math.atan2(-h,k))):"YZX"===b?(this._z=Math.asin(d(j)),Math.abs(j)<.99999?(this._x=Math.atan2(-l,k),this._y=Math.atan2(-m,g)):(this._x=0,this._y=Math.atan2(i,o))):"XZY"===b?(this._z=Math.asin(-d(h)),Math.abs(h)<.99999?(this._x=Math.atan2(n,k),this._y=Math.atan2(i,g)):(this._x=Math.atan2(-l,o),this._y=0)):e.onwarning("WARNING: Euler.setFromRotationMatrix() given unsupported order: "+b),this._order=b,c!==!1&&this._updateQuaternion(),this},setFromQuaternion:function(){var a=null;return function(b,c,d){return a=a||new e.Matrix4,a.makeRotationFromQuaternion(b),this.setFromRotationMatrix(a,c,d),this}}(),reorder:function(){var a=new e.Quaternion;return function(b){a.setFromEuler(this),this.setFromQuaternion(a,b)}}(),fromArray:function(a){return this._x=a[0],this._y=a[1],this._z=a[2],void 0!==a[3]&&(this._order=a[3]),this._updateQuaternion(),this},toArray:function(){return[this._x,this._y,this._z,this._order]},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},toVector3:function(a){return a?a.set(this._x,this._y,this._z):new e.Vector3(this._x,this._y,this._z)},clone:function(){return new e.Euler(this._x,this._y,this._z,this._order)}},e.Line3=function(a,b){this.start=void 0!==a?a:new e.Vector3,this.end=void 0!==b?b:new e.Vector3},e.Line3.prototype={constructor:e.Line3,set:function(a,b){return this.start.copy(a),this.end.copy(b),this},copy:function(a){return this.start.copy(a.start),this.end.copy(a.end),this},center:function(a){var b=a||new e.Vector3;return b.addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(a){var b=a||new e.Vector3;return b.subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(a,b){var c=b||new e.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new e.Vector3,b=new e.Vector3;return function(c,d){a.subVectors(c,this.start),b.subVectors(this.end,this.start);var f=b.dot(b),g=b.dot(a),h=g/f;return d&&(h=e.Math.clamp(h,0,1)),h}}(),closestPointToPoint:function(a,b,c){var d=this.closestPointToPointParameter(a,b),f=c||new e.Vector3;return this.delta(f).multiplyScalar(d).add(this.start)},applyMatrix4:function(a){return this.start.applyMatrix4(a),this.end.applyMatrix4(a),this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)},clone:function(){return(new e.Line3).copy(this)}},e.Box2=function(a,b){this.min=void 0!==a?a:new e.Vector2(1/0,1/0),this.max=void 0!==b?b:new e.Vector2(-(1/0),-(1/0))},e.Box2.prototype={constructor:e.Box2,set:function(a,b){return this.min.copy(a),this.max.copy(b),this},setFromPoints:function(a){if(a.length>0){var b=a[0];this.min.copy(b),this.max.copy(b);for(var c=1,d=a.length;d>c;c++)b=a[c],b.xthis.max.x&&(this.max.x=b.x),b.ythis.max.y&&(this.max.y=b.y)}else this.makeEmpty();return this},setFromCenterAndSize:function(){var a=new e.Vector2;return function(b,c){var d=a.copy(c).multiplyScalar(.5);return this.min.copy(b).sub(d),this.max.copy(b).add(d),this}}(),copy:function(a){return this.min.copy(a.min),this.max.copy(a.max),this},makeEmpty:function(){return this.min.x=this.min.y=1/0,this.max.x=this.max.y=-(1/0),this},empty:function(){return this.max.xthis.max.x||a.ythis.max.y)},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y},getParameter:function(a,b){var c=b||new e.Vector2;return c.set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y))},isIntersectionBox:function(a){return!(a.max.xthis.max.x||a.max.ythis.max.y)},clampPoint:function(a,b){var c=b||new e.Vector2;return c.copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new e.Vector2;return function(b){var c=a.copy(b).clamp(this.min,this.max);return c.sub(b).length()}}(),intersect:function(a){return this.min.max(a.min),this.max.min(a.max),this},union:function(a){return this.min.min(a.min),this.max.max(a.max),this},translate:function(a){return this.min.add(a),this.max.add(a),this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new e.Box2).copy(this)}},e.Box3=function(a,b){this.min=void 0!==a?a:new e.Vector3(1/0,1/0,1/0),this.max=void 0!==b?b:new e.Vector3(-(1/0),-(1/0),-(1/0))},e.Box3.prototype={constructor:e.Box3,set:function(a,b){return this.min.copy(a),this.max.copy(b),this},addPoint:function(a){a.xthis.max.x&&(this.max.x=a.x),a.ythis.max.y&&(this.max.y=a.y),a.zthis.max.z&&(this.max.z=a.z)},setFromPoints:function(a){if(a.length>0){var b=a[0];this.min.copy(b),this.max.copy(b);for(var c=1,d=a.length;d>c;c++)this.addPoint(a[c])}else this.makeEmpty();return this},setFromCenterAndSize:function(){var a=new e.Vector3;return function(b,c){var d=a.copy(c).multiplyScalar(.5);return this.min.copy(b).sub(d),this.max.copy(b).add(d),this}}(),setFromObject:function(){var a=new e.Vector3;return function(b){var c=this;return b.updateMatrixWorld(!0),this.makeEmpty(),b.traverse(function(b){if(void 0!==b.geometry&&void 0!==b.geometry.vertices)for(var d=b.geometry.vertices,e=0,f=d.length;f>e;e++)a.copy(d[e]),a.applyMatrix4(b.matrixWorld),c.expandByPoint(a)}),this}}(),copy:function(a){return this.min.copy(a.min),this.max.copy(a.max),this},makeEmpty:function(){return this.min.x=this.min.y=this.min.z=1/0,this.max.x=this.max.y=this.max.z=-(1/0),this},empty:function(){return this.max.xthis.max.x||a.ythis.max.y||a.zthis.max.z)},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z},getParameter:function(a,b){var c=b||new e.Vector3;return c.set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},isIntersectionBox:function(a){return!(a.max.xthis.max.x||a.max.ythis.max.y||a.max.zthis.max.z)},clampPoint:function(a,b){var c=b||new e.Vector3;return c.copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new e.Vector3;return function(b){var c=a.copy(b).clamp(this.min,this.max);return c.sub(b).length()}}(),getBoundingSphere:function(){var a=new e.Vector3;return function(b){var c=b||new e.Sphere;return c.center=this.center(),c.radius=.5*this.size(a).length(),c}}(),intersect:function(a){return this.min.max(a.min),this.max.min(a.max),this},union:function(a){return this.min.min(a.min),this.max.max(a.max),this},applyMatrix4:function(){var a=[new e.Vector3,new e.Vector3,new e.Vector3,new e.Vector3,new e.Vector3,new e.Vector3,new e.Vector3,new e.Vector3];return function(b){return a[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(b),a[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(b),a[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(b),a[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(b),a[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(b),a[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(b),a[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(b),a[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(b),this.makeEmpty(),this.setFromPoints(a),this}}(),translate:function(a){return this.min.add(a),this.max.add(a),this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new e.Box3).copy(this)}},e.Matrix3=function(a,b,c,d,e,f,g,h,i){this.elements=new Float32Array(9),this.set(void 0!==a?a:1,b||0,c||0,d||0,void 0!==e?e:1,f||0,g||0,h||0,void 0!==i?i:1)},e.Matrix3.prototype={constructor:e.Matrix3,set:function(a,b,c,d,e,f,g,h,i){var j=this.elements;return j[0]=a,j[3]=b,j[6]=c,j[1]=d,j[4]=e,j[7]=f,j[2]=g,j[5]=h,j[8]=i,this},identity:function(){return this.set(1,0,0,0,1,0,0,0,1),this},copy:function(a){var b=a.elements;return this.set(b[0],b[3],b[6],b[1],b[4],b[7],b[2],b[5],b[8]),this},multiplyVector3:function(a){return e.onwarning("DEPRECATED: Matrix3's .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead."),a.applyMatrix3(this)},multiplyVector3Array:function(){var a=new e.Vector3;return function(b){for(var c=0,d=b.length;d>c;c+=3)a.x=b[c],a.y=b[c+1],a.z=b[c+2],a.applyMatrix3(this),b[c]=a.x,b[c+1]=a.y,b[c+2]=a.z;return b}}(),multiplyScalar:function(a){var b=this.elements;return b[0]*=a,b[3]*=a,b[6]*=a,b[1]*=a,b[4]*=a,b[7]*=a,b[2]*=a,b[5]*=a,b[8]*=a,this},determinant:function(){var a=this.elements,b=a[0],c=a[1],d=a[2],e=a[3],f=a[4],g=a[5],h=a[6],i=a[7],j=a[8];return b*f*j-b*g*i-c*e*j+c*g*h+d*e*i-d*f*h},getInverse:function(a,b){if(!(a instanceof e.Matrix4))return e.onerror("expecting a Matrix4",a);var c=a.elements,d=this.elements;d[0]=c[10]*c[5]-c[6]*c[9],d[1]=-c[10]*c[1]+c[2]*c[9],d[2]=c[6]*c[1]-c[2]*c[5],d[3]=-c[10]*c[4]+c[6]*c[8],d[4]=c[10]*c[0]-c[2]*c[8],d[5]=-c[6]*c[0]+c[2]*c[4],d[6]=c[9]*c[4]-c[5]*c[8],d[7]=-c[9]*c[0]+c[1]*c[8],d[8]=c[5]*c[0]-c[1]*c[4];var f=c[0]*d[0]+c[1]*d[3]+c[2]*d[6];return 0===f?b===!0?e.onerror("Matrix3.getInverse(): can't invert matrix, determinant is 0",this):(this.identity(),this):(this.multiplyScalar(1/f),this)},transpose:function(){var a,b=this.elements;return a=b[1],b[1]=b[3],b[3]=a,a=b[2],b[2]=b[6],b[6]=a,a=b[5],b[5]=b[7],b[7]=a,this},getNormalMatrix:function(a){return this.getInverse(a).transpose(),this},transposeIntoArray:function(a){var b=this.elements;return a[0]=b[0],a[1]=b[3],a[2]=b[6],a[3]=b[1],a[4]=b[4],a[5]=b[7],a[6]=b[2],a[7]=b[5],a[8]=b[8],this},fromArray:function(a){return this.elements.set(a),this},toArray:function(){var a=this.elements;return[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]]},clone:function(){var a=this.elements;return new e.Matrix3(a[0],a[3],a[6],a[1],a[4],a[7],a[2],a[5],a[8])}},e.Matrix4=function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p){this.elements=new Float32Array(16);var q=this.elements;q[0]=void 0!==a?a:1,q[4]=b||0,q[8]=c||0,q[12]=d||0,q[1]=e||0,q[5]=void 0!==f?f:1,q[9]=g||0,q[13]=h||0,q[2]=i||0,q[6]=j||0,q[10]=void 0!==k?k:1,q[14]=l||0,q[3]=m||0,q[7]=n||0,q[11]=o||0,q[15]=void 0!==p?p:1},e.Matrix4.prototype={constructor:e.Matrix4,set:function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p){var q=this.elements;return q[0]=a,q[4]=b,q[8]=c,q[12]=d,q[1]=e,q[5]=f,q[9]=g,q[13]=h,q[2]=i,q[6]=j,q[10]=k,q[14]=l,q[3]=m,q[7]=n,q[11]=o,q[15]=p,this},identity:function(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this},copy:function(a){return this.elements.set(a.elements),this},extractPosition:function(a){return e.onwarning("DEPRECATED: Matrix4's .extractPosition() has been renamed to .copyPosition()."),this.copyPosition(a)},copyPosition:function(a){var b=this.elements,c=a.elements;return b[12]=c[12],b[13]=c[13],b[14]=c[14],this},extractBasis:function(a,b,c){var d=this.elements;return a.set(d[0],d[1],d[2]),b.set(d[4],d[5],d[6]),c.set(d[8],d[9],d[10]),this},makeBasis:function(a,b,c){this.identity();var d=this.elements;return d.elements[0]=a.x,d.elements[1]=a.y,d.elements[2]=a.z,d.elements[4]=b.x,d.elements[5]=b.y,d.elements[6]=b.z,d.elements[8]=c.x,d.elements[9]=c.y,d.elements[10]=c.z,this},extractRotation:function(){var a=new e.Vector3;return function(b){var c=this.elements,d=b.elements,e=1/a.set(d[0],d[1],d[2]).length(),f=1/a.set(d[4],d[5],d[6]).length(),g=1/a.set(d[8],d[9],d[10]).length();return c[0]=d[0]*e,c[1]=d[1]*e,c[2]=d[2]*e,c[4]=d[4]*f,c[5]=d[5]*f,c[6]=d[6]*f,c[8]=d[8]*g,c[9]=d[9]*g,c[10]=d[10]*g,this}}(),makeRotationFromEuler:function(a){if(!(a instanceof e.Euler))return e.onerror("expecting a Euler",a);var b=this.elements,c=a.x,d=a.y,f=a.z,g=Math.cos(c),h=Math.sin(c),i=Math.cos(d),j=Math.sin(d),k=Math.cos(f),l=Math.sin(f);if("XYZ"===a.order){var m=g*k,n=g*l,o=h*k,p=h*l;b[0]=i*k,b[4]=-i*l,b[8]=j,b[1]=n+o*j,b[5]=m-p*j,b[9]=-h*i,b[2]=p-m*j,b[6]=o+n*j,b[10]=g*i}else if("YXZ"===a.order){var q=i*k,r=i*l,s=j*k,t=j*l;b[0]=q+t*h,b[4]=s*h-r,b[8]=g*j,b[1]=g*l,b[5]=g*k,b[9]=-h,b[2]=r*h-s,b[6]=t+q*h,b[10]=g*i}else if("ZXY"===a.order){var q=i*k,r=i*l,s=j*k,t=j*l;b[0]=q-t*h,b[4]=-g*l,b[8]=s+r*h,b[1]=r+s*h,b[5]=g*k,b[9]=t-q*h,b[2]=-g*j,b[6]=h,b[10]=g*i}else if("ZYX"===a.order){var m=g*k,n=g*l,o=h*k,p=h*l;b[0]=i*k,b[4]=o*j-n,b[8]=m*j+p,b[1]=i*l,b[5]=p*j+m,b[9]=n*j-o,b[2]=-j,b[6]=h*i,b[10]=g*i}else if("YZX"===a.order){var u=g*i,v=g*j,w=h*i,x=h*j;b[0]=i*k,b[4]=x-u*l,b[8]=w*l+v,b[1]=l,b[5]=g*k,b[9]=-h*k,b[2]=-j*k,b[6]=v*l+w,b[10]=u-x*l}else if("XZY"===a.order){var u=g*i,v=g*j,w=h*i,x=h*j;b[0]=i*k,b[4]=-l,b[8]=j*k,b[1]=u*l+x,b[5]=g*k,b[9]=v*l-w,b[2]=w*l-v,b[6]=h*k,b[10]=x*l+u}return b[3]=0,b[7]=0,b[11]=0,b[12]=0,b[13]=0,b[14]=0,b[15]=1,this},setRotationFromQuaternion:function(a){return e.onwarning("DEPRECATED: Matrix4's .setRotationFromQuaternion() has been deprecated in favor of makeRotationFromQuaternion. Please update your code."),this.makeRotationFromQuaternion(a)},makeRotationFromQuaternion:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=a.w,g=c+c,h=d+d,i=e+e,j=c*g,k=c*h,l=c*i,m=d*h,n=d*i,o=e*i,p=f*g,q=f*h,r=f*i;return b[0]=1-(m+o),b[4]=k-r,b[8]=l+q,b[1]=k+r,b[5]=1-(j+o),b[9]=n-p,b[2]=l-q,b[6]=n+p,b[10]=1-(j+m),b[3]=0,b[7]=0,b[11]=0,b[12]=0,b[13]=0,b[14]=0,b[15]=1,this},lookAt:function(){var a=new e.Vector3,b=new e.Vector3,c=new e.Vector3;return function(d,e,f){var g=this.elements;return c.subVectors(d,e).normalize(),0===c.length()&&(c.z=1),a.crossVectors(f,c).normalize(),0===a.length()&&(c.x+=1e-4,a.crossVectors(f,c).normalize()),b.crossVectors(c,a),g[0]=a.x,g[4]=b.x,g[8]=c.x,g[1]=a.y,g[5]=b.y,g[9]=c.y,g[2]=a.z,g[6]=b.z,g[10]=c.z,this}}(),multiply:function(a,b){return void 0!==b?(e.onwarning("DEPRECATED: Matrix4's .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(a,b)):this.multiplyMatrices(this,a)},multiplyList:function(a){for(var b=0,c=a.length;c>b;b++)this.multiplyMatrices(this,a[b]);return this},multiplyMatricesList:function(a){return a.length>0?(this.copy(a[0]),this.multiplyList(a.slice(1))):this.identity(),this},multiplyMatrices:function(a,b){if(!(a instanceof e.Matrix4))return e.onerror("expecting a Matrix4",a);if(!(b instanceof e.Matrix4))return e.onerror("expecting a Matrix4",b);var c=a.elements,d=b.elements,f=this.elements,g=c[0],h=c[4],i=c[8],j=c[12],k=c[1],l=c[5],m=c[9],n=c[13],o=c[2],p=c[6],q=c[10],r=c[14],s=c[3],t=c[7],u=c[11],v=c[15],w=d[0],x=d[4],y=d[8],z=d[12],A=d[1],B=d[5],C=d[9],D=d[13],E=d[2],F=d[6],G=d[10],H=d[14],I=d[3],J=d[7],K=d[11],L=d[15];return f[0]=g*w+h*A+i*E+j*I,f[4]=g*x+h*B+i*F+j*J,f[8]=g*y+h*C+i*G+j*K,f[12]=g*z+h*D+i*H+j*L,f[1]=k*w+l*A+m*E+n*I,f[5]=k*x+l*B+m*F+n*J,f[9]=k*y+l*C+m*G+n*K,f[13]=k*z+l*D+m*H+n*L,f[2]=o*w+p*A+q*E+r*I,f[6]=o*x+p*B+q*F+r*J,f[10]=o*y+p*C+q*G+r*K,f[14]=o*z+p*D+q*H+r*L,f[3]=s*w+t*A+u*E+v*I,f[7]=s*x+t*B+u*F+v*J,f[11]=s*y+t*C+u*G+v*K,f[15]=s*z+t*D+u*H+v*L,this},multiplyToArray:function(a,b,c){var d=this.elements;return this.multiplyMatrices(a,b),c[0]=d[0],c[1]=d[1],c[2]=d[2],c[3]=d[3],c[4]=d[4],c[5]=d[5],c[6]=d[6],c[7]=d[7],c[8]=d[8],c[9]=d[9],c[10]=d[10],c[11]=d[11],c[12]=d[12],c[13]=d[13],c[14]=d[14],c[15]=d[15],this},multiplyScalar:function(a){var b=this.elements;return b[0]*=a,b[4]*=a,b[8]*=a,b[12]*=a,b[1]*=a,b[5]*=a,b[9]*=a,b[13]*=a,b[2]*=a,b[6]*=a,b[10]*=a,b[14]*=a,b[3]*=a,b[7]*=a,b[11]*=a,b[15]*=a,this},multiplyVector3:function(a){return e.onwarning("DEPRECATED: Matrix4's .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead."),a.applyProjection(this)},multiplyVector4:function(a){return e.onwarning("DEPRECATED: Matrix4's .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead."),a.applyMatrix4(this)},multiplyVector3Array:function(){var a=new e.Vector3;return function(b){for(var c=0,d=b.length;d>c;c+=3)a.x=b[c],a.y=b[c+1],a.z=b[c+2],a.applyProjection(this),b[c]=a.x,b[c+1]=a.y,b[c+2]=a.z;return b}}(),rotateAxis:function(a){e.onwarning("DEPRECATED: Matrix4's .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead."),a.transformDirection(this)},crossVector:function(a){return e.onwarning("DEPRECATED: Matrix4's .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead."),a.applyMatrix4(this)},determinant:function(){var a=this.elements,b=a[0],c=a[4],d=a[8],e=a[12],f=a[1],g=a[5],h=a[9],i=a[13],j=a[2],k=a[6],l=a[10],m=a[14],n=a[3],o=a[7],p=a[11],q=a[15];return n*(+e*h*k-d*i*k-e*g*l+c*i*l+d*g*m-c*h*m)+o*(+b*h*m-b*i*l+e*f*l-d*f*m+d*i*j-e*h*j)+p*(+b*i*k-b*g*m-e*f*k+c*f*m+e*g*j-c*i*j)+q*(-d*g*j-b*h*k+b*g*l+d*f*k-c*f*l+c*h*j)},transpose:function(){var a,b=this.elements;return a=b[1],b[1]=b[4],b[4]=a,a=b[2],b[2]=b[8],b[8]=a,a=b[6],b[6]=b[9],b[9]=a,a=b[3],b[3]=b[12],b[12]=a,a=b[7],b[7]=b[13],b[13]=a,a=b[11],b[11]=b[14],b[14]=a,this},flattenToArray:function(a){var b=this.elements;return a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[3],a[4]=b[4],a[5]=b[5],a[6]=b[6],a[7]=b[7],a[8]=b[8],a[9]=b[9],a[10]=b[10],a[11]=b[11],a[12]=b[12],a[13]=b[13],a[14]=b[14],a[15]=b[15],a},flattenToArrayOffset:function(a,b){var c=this.elements;return a[b]=c[0],a[b+1]=c[1],a[b+2]=c[2],a[b+3]=c[3],a[b+4]=c[4],a[b+5]=c[5],a[b+6]=c[6],a[b+7]=c[7],a[b+8]=c[8],a[b+9]=c[9],a[b+10]=c[10],a[b+11]=c[11],a[b+12]=c[12],a[b+13]=c[13],a[b+14]=c[14],a[b+15]=c[15],a},getPosition:function(){var a=new e.Vector3;return function(){e.onwarning("DEPRECATED: Matrix4's .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.");var b=this.elements;return a.set(b[12],b[13],b[14])}}(),setPosition:function(a){var b=this.elements;return b[12]=a.x,b[13]=a.y,b[14]=a.z,this},getInverse:function(a,b){var c=this.elements,d=a.elements,f=d[0],g=d[4],h=d[8],i=d[12],j=d[1],k=d[5],l=d[9],m=d[13],n=d[2],o=d[6],p=d[10],q=d[14],r=d[3],s=d[7],t=d[11],u=d[15];c[0]=l*q*s-m*p*s+m*o*t-k*q*t-l*o*u+k*p*u,c[4]=i*p*s-h*q*s-i*o*t+g*q*t+h*o*u-g*p*u,c[8]=h*m*s-i*l*s+i*k*t-g*m*t-h*k*u+g*l*u,c[12]=i*l*o-h*m*o-i*k*p+g*m*p+h*k*q-g*l*q,c[1]=m*p*r-l*q*r-m*n*t+j*q*t+l*n*u-j*p*u,c[5]=h*q*r-i*p*r+i*n*t-f*q*t-h*n*u+f*p*u,c[9]=i*l*r-h*m*r-i*j*t+f*m*t+h*j*u-f*l*u,c[13]=h*m*n-i*l*n+i*j*p-f*m*p-h*j*q+f*l*q,c[2]=k*q*r-m*o*r+m*n*s-j*q*s-k*n*u+j*o*u,c[6]=i*o*r-g*q*r-i*n*s+f*q*s+g*n*u-f*o*u,c[10]=g*m*r-i*k*r+i*j*s-f*m*s-g*j*u+f*k*u,c[14]=i*k*n-g*m*n-i*j*o+f*m*o+g*j*q-f*k*q,c[3]=l*o*r-k*p*r-l*n*s+j*p*s+k*n*t-j*o*t,c[7]=g*p*r-h*o*r+h*n*s-f*p*s-g*n*t+f*o*t,c[11]=h*k*r-g*l*r-h*j*s+f*l*s+g*j*t-f*k*t,c[15]=g*l*n-h*k*n+h*j*o-f*l*o-g*j*p+f*k*p;var v=f*c[0]+j*c[4]+n*c[8]+r*c[12];return 0==v?b===!0?e.onerror("Matrix4.getInverse(): can't invert matrix, determinant is 0",this):(this.identity(),this):(this.multiplyScalar(1/v),this)},translate:function(a){e.onerror("DEPRECATED: Matrix4's .translate() has been removed.")},rotateX:function(a){e.onerror("DEPRECATED: Matrix4's .rotateX() has been removed.")},rotateY:function(a){e.onerror("DEPRECATED: Matrix4's .rotateY() has been removed.")},rotateZ:function(a){e.onerror("DEPRECATED: Matrix4's .rotateZ() has been removed.")},rotateByAxis:function(a,b){e.onerror("DEPRECATED: Matrix4's .rotateByAxis() has been removed.")},scale:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z;return b[0]*=c,b[4]*=d,b[8]*=e,b[1]*=c,b[5]*=d,b[9]*=e,b[2]*=c,b[6]*=d,b[10]*=e,b[3]*=c,b[7]*=d,b[11]*=e,this},getMaxScaleOnAxis:function(){var a=this.elements,b=a[0]*a[0]+a[1]*a[1]+a[2]*a[2],c=a[4]*a[4]+a[5]*a[5]+a[6]*a[6],d=a[8]*a[8]+a[9]*a[9]+a[10]*a[10];return Math.sqrt(Math.max(b,Math.max(c,d)))},makeTranslation:function(a,b,c){return this.set(1,0,0,a,0,1,0,b,0,0,1,c,0,0,0,1),this},makeRotationX:function(a){var b=Math.cos(a),c=Math.sin(a);return this.set(1,0,0,0,0,b,-c,0,0,c,b,0,0,0,0,1),this},makeRotationY:function(a){var b=Math.cos(a),c=Math.sin(a);return this.set(b,0,c,0,0,1,0,0,-c,0,b,0,0,0,0,1),this},makeRotationZ:function(a){var b=Math.cos(a),c=Math.sin(a);return this.set(b,-c,0,0,c,b,0,0,0,0,1,0,0,0,0,1),this},makeRotationAxis:function(a,b){var c=Math.cos(b),d=Math.sin(b),e=1-c,f=a.x,g=a.y,h=a.z,i=e*f,j=e*g;return this.set(i*f+c,i*g-d*h,i*h+d*g,0,i*g+d*h,j*g+c,j*h-d*f,0,i*h-d*g,j*h+d*f,e*h*h+c,0,0,0,0,1),this},makeScale:function(a,b,c){return this.set(a,0,0,0,0,b,0,0,0,0,c,0,0,0,0,1),this},makeShear:function(a,b){var c=a.x,d=a.y,e=a.z;return b?this.set(1,0,0,0,c,1,0,0,d,e,1,0,0,0,0,1):this.set(1,c,d,0,0,1,e,0,0,0,1,0,0,0,0,1),this},compose:function(a,b,c){return this.makeRotationFromQuaternion(b),this.scale(c),this.setPosition(a),this},decompose:function(){var a=new e.Vector3,b=new e.Matrix4;return function(c,d,e){var f=this.elements,g=a.set(f[0],f[1],f[2]).length(),h=a.set(f[4],f[5],f[6]).length(),i=a.set(f[8],f[9],f[10]).length(),j=this.determinant();0>j&&(g=-g),c.x=f[12],c.y=f[13],c.z=f[14],b.elements.set(this.elements);var k=1/g,l=1/h,m=1/i;return b.elements[0]*=k,b.elements[1]*=k,b.elements[2]*=k,b.elements[4]*=l,b.elements[5]*=l,b.elements[6]*=l,b.elements[8]*=m,b.elements[9]*=m,b.elements[10]*=m,d.setFromRotationMatrix(b),e.x=g,e.y=h,e.z=i,this}}(),makeFrustum:function(a,b,c,d,e,f,g,h){var i=this.elements,j=2*e/(b-a),k=2*e/(d-c),l=(b+a)/(b-a),m=(d+c)/(d-c),n=-(f+e)/(f-e),o=-2*f*e/(f-e);return i[0]=j,i[4]=0,i[8]=l,i[12]=0,i[1]=0,i[5]=k,i[9]=m,i[13]=0,i[2]=0,i[6]=0,i[10]=n,i[14]=o,i[3]=0,i[7]=0,i[11]=-1,i[15]=0,g&&h&&(0!==h.x&&(i[8]+=2*g.x/h.x),0!==h.y&&(i[9]+=2*g.y/h.y)),this},makePerspective:function(a,b,c,d,f,g){var h=c*Math.tan(e.Math.degToRad(.5*a)),i=-h,j=i*b,k=h*b;return this.makeFrustum(j,k,i,h,c,d,f,g)},makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,h=b-a,i=c-d,j=f-e,k=(b+a)/h,l=(c+d)/i,m=(f+e)/j;return g[0]=2/h,g[4]=0,g[8]=0,g[12]=-k,g[1]=0,g[5]=2/i,g[9]=0,g[13]=-l,g[2]=0,g[6]=0,g[10]=-2/j,g[14]=-m,g[3]=0,g[7]=0,g[11]=0,g[15]=1,this},fromArray:function(a){return this.elements.set(a),this},toArray:function(){var a=this.elements;return[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11],a[12],a[13],a[14],a[15]]},clone:function(){var a=this.elements;return new e.Matrix4(a[0],a[4],a[8],a[12],a[1],a[5],a[9],a[13],a[2],a[6],a[10],a[14],a[3],a[7],a[11],a[15])}},e.Ray=function(a,b){this.origin=void 0!==a?a:new e.Vector3,this.direction=void 0!==b?b:new e.Vector3},e.Ray.prototype={constructor:e.Ray,set:function(a,b){return this.origin.copy(a),this.direction.copy(b),this},copy:function(a){return this.origin.copy(a.origin),this.direction.copy(a.direction),this},at:function(a,b){var c=b||new e.Vector3;return c.copy(this.direction).multiplyScalar(a).add(this.origin)},recast:function(){var a=new e.Vector3;return function(b){return this.origin.copy(this.at(b,a)),this}}(),closestPointToPoint:function(a,b){var c=b||new e.Vector3;c.subVectors(a,this.origin);var d=c.dot(this.direction);return 0>d?c.copy(this.origin):c.copy(this.direction).multiplyScalar(d).add(this.origin)},distanceToPoint:function(){var a=new e.Vector3;return function(b){var c=a.subVectors(b,this.origin).dot(this.direction);return 0>c?this.origin.distanceTo(b):(a.copy(this.direction).multiplyScalar(c).add(this.origin),a.distanceTo(b))}}(),distanceSqToSegment:function(a,b,c,d){var e,f,g,h,i=a.clone().add(b).multiplyScalar(.5),j=b.clone().sub(a).normalize(),k=.5*a.distanceTo(b),l=this.origin.clone().sub(i),m=-this.direction.dot(j),n=l.dot(this.direction),o=-l.dot(j),p=l.lengthSq(),q=Math.abs(1-m*m);if(q>=0)if(e=m*o-n,f=m*n-o,h=k*q,e>=0)if(f>=-h)if(h>=f){var r=1/q;e*=r,f*=r,g=e*(e+m*f+2*n)+f*(m*e+f+2*o)+p}else f=k,e=Math.max(0,-(m*f+n)),g=-e*e+f*(f+2*o)+p;else f=-k,e=Math.max(0,-(m*f+n)),g=-e*e+f*(f+2*o)+p;else-h>=f?(e=Math.max(0,-(-m*k+n)),f=e>0?-k:Math.min(Math.max(-k,-o),k),g=-e*e+f*(f+2*o)+p):h>=f?(e=0,f=Math.min(Math.max(-k,-o),k),g=f*(f+2*o)+p):(e=Math.max(0,-(m*k+n)),f=e>0?k:Math.min(Math.max(-k,-o),k),g=-e*e+f*(f+2*o)+p);else f=m>0?-k:k,e=Math.max(0,-(m*f+n)),g=-e*e+f*(f+2*o)+p;return c&&c.copy(this.direction.clone().multiplyScalar(e).add(this.origin)),d&&d.copy(j.clone().multiplyScalar(f).add(i)),g},isIntersectionSphere:function(a){return this.distanceToPoint(a.center)<=a.radius},isIntersectionPlane:function(a){var b=a.distanceToPoint(this.origin);if(0===b)return!0;var c=a.normal.dot(this.direction);return 0>c*b},distanceToPlane:function(a){var b=a.normal.dot(this.direction);if(0==b)return 0==a.distanceToPoint(this.origin)?0:null;var c=-(this.origin.dot(a.normal)+a.constant)/b;return c>=0?c:null},intersectPlane:function(a,b){var c=this.distanceToPlane(a);return null===c?null:this.at(c,b)},isIntersectionBox:function(){var a=new e.Vector3;return function(b){return null!==this.intersectBox(b,a)}}(),intersectBox:function(a,b){var c,d,e,f,g,h,i=1/this.direction.x,j=1/this.direction.y,k=1/this.direction.z,l=this.origin;return i>=0?(c=(a.min.x-l.x)*i,d=(a.max.x-l.x)*i):(c=(a.max.x-l.x)*i,d=(a.min.x-l.x)*i),j>=0?(e=(a.min.y-l.y)*j,f=(a.max.y-l.y)*j):(e=(a.max.y-l.y)*j,f=(a.min.y-l.y)*j),c>f||e>d?null:((e>c||c!==c)&&(c=e),(d>f||d!==d)&&(d=f),k>=0?(g=(a.min.z-l.z)*k,h=(a.max.z-l.z)*k):(g=(a.max.z-l.z)*k,h=(a.min.z-l.z)*k),c>h||g>d?null:((g>c||c!==c)&&(c=g),(d>h||d!==d)&&(d=h),0>d?null:this.at(c>=0?c:d,b)))},intersectTriangle:function(){var a=new e.Vector3,b=new e.Vector3,c=new e.Vector3,d=new e.Vector3;return function(e,f,g,h,i){b.subVectors(f,e),c.subVectors(g,e),d.crossVectors(b,c);var j,k=this.direction.dot(d);if(k>0){if(h)return null;j=1}else{if(!(0>k))return null;j=-1,k=-k}a.subVectors(this.origin,e);var l=j*this.direction.dot(c.crossVectors(a,c));if(0>l)return null;var m=j*this.direction.dot(b.cross(a));if(0>m)return null;if(l+m>k)return null;var n=-j*a.dot(d);return 0>n?null:this.at(n/k,i)}}(),applyMatrix4:function(a){return this.direction.add(this.origin).applyMatrix4(a),this.origin.applyMatrix4(a),this.direction.sub(this.origin),this.direction.normalize(),this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)},clone:function(){return(new e.Ray).copy(this)}},e.Sphere=function(a,b){this.center=void 0!==a?a:new e.Vector3,this.radius=void 0!==b?b:0},e.Sphere.prototype={constructor:e.Sphere,set:function(a,b){return this.center.copy(a),this.radius=b,this},setFromPoints:function(){var a=new e.Box3;return function(b,c){var d=this.center;void 0!==c?d.copy(c):a.setFromPoints(b).center(d);for(var e=0,f=d.x,g=d.y,h=d.z,i=0,j=b.length;j>i;i++){var k=b[i],l=f-k.x,m=g-k.y,n=h-k.z,o=l*l+m*m+n*n;e=Math.max(e,o)}return this.radius=Math.sqrt(e),this}}(),copy:function(a){return this.center.copy(a.center),this.radius=a.radius,this},empty:function(){return this.radius<=0},containsPoint:function(a){return a.distanceToSquared(this.center)<=this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},clampPoint:function(a,b){var c=this.center.distanceToSquared(a),d=b||new e.Vector3;return d.copy(a),c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this.radius).add(this.center)),d},getBoundingBox:function(a){var b=a||new e.Box3;return b.set(this.center,this.center),b.expandByScalar(this.radius),b},applyMatrix4:function(a){return this.center.applyMatrix4(a),this.radius=this.radius*a.getMaxScaleOnAxis(),this},translate:function(a){return this.center.add(a),this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new e.Sphere).copy(this)}},e.Frustum=function(a,b,c,d,f,g){this.planes=[void 0!==a?a:new e.Plane,void 0!==b?b:new e.Plane,void 0!==c?c:new e.Plane,void 0!==d?d:new e.Plane,void 0!==f?f:new e.Plane,void 0!==g?g:new e.Plane]},e.Frustum.prototype={constructor:e.Frustum,set:function(a,b,c,d,e,f){var g=this.planes;return g[0].copy(a),g[1].copy(b),g[2].copy(c),g[3].copy(d),g[4].copy(e),g[5].copy(f),this},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements,d=c[0],e=c[1],f=c[2],g=c[3],h=c[4],i=c[5],j=c[6],k=c[7],l=c[8],m=c[9],n=c[10],o=c[11],p=c[12],q=c[13],r=c[14],s=c[15];return b[0].setComponents(g-d,k-h,o-l,s-p).normalize(),b[1].setComponents(g+d,k+h,o+l,s+p).normalize(),b[2].setComponents(g+e,k+i,o+m,s+q).normalize(),b[3].setComponents(g-e,k-i,o-m,s-q).normalize(),b[4].setComponents(g-f,k-j,o-n,s-r).normalize(),b[5].setComponents(g+f,k+j,o+n,s+r).normalize(),this},intersectsObject:function(){var a=new e.Sphere;return function(b){var c=b.geometry;return null===c.boundingSphere&&c.computeBoundingSphere(),a.copy(c.boundingSphere),a.applyMatrix4(b.matrixWorld),this.intersectsSphere(a)}}(),intersectsSphere:function(a){for(var b=this.planes,c=a.center,d=-a.radius,e=0;6>e;e++){var f=b[e].distanceToPoint(c);if(d>f)return!1}return!0},intersectsBox:function(){var a=new e.Vector3,b=new e.Vector3;return function(c){for(var d=this.planes,e=0;6>e;e++){var f=d[e];a.x=f.normal.x>0?c.min.x:c.max.x,b.x=f.normal.x>0?c.max.x:c.min.x,a.y=f.normal.y>0?c.min.y:c.max.y,b.y=f.normal.y>0?c.max.y:c.min.y,a.z=f.normal.z>0?c.min.z:c.max.z,b.z=f.normal.z>0?c.max.z:c.min.z;var g=f.distanceToPoint(a),h=f.distanceToPoint(b);if(0>g&&0>h)return!1}return!0}}(),containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(b[c].distanceToPoint(a)<0)return!1;return!0},clone:function(){return(new e.Frustum).copy(this)}},e.Plane=function(a,b){this.normal=void 0!==a?a:new e.Vector3(1,0,0),this.constant=void 0!==b?b:0},e.Plane.prototype={constructor:e.Plane,set:function(a,b){return this.normal.copy(a),this.constant=b,this},setComponents:function(a,b,c,d){return this.normal.set(a,b,c),this.constant=d,this},setFromNormalAndCoplanarPoint:function(a,b){return this.normal.copy(a),this.constant=-b.dot(this.normal),this},setFromCoplanarPoints:function(){var a=new e.Vector3,b=new e.Vector3;return function(c,d,e){var f=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();return this.setFromNormalAndCoplanarPoint(f,c),this}}(),copy:function(a){ +return this.normal.copy(a.normal),this.constant=a.constant,this},normalize:function(){var a=1/this.normal.length();return this.normal.multiplyScalar(a),this.constant*=a,this},negate:function(){return this.constant*=-1,this.normal.negate(),this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){return this.orthoPoint(a,b).sub(a).negate()},orthoPoint:function(a,b){var c=this.distanceToPoint(a),d=b||new e.Vector3;return d.copy(this.normal).multiplyScalar(c)},isIntersectionLine:function(a){var b=this.distanceToPoint(a.start),c=this.distanceToPoint(a.end);return 0>b&&c>0||0>c&&b>0},intersectLine:function(){var a=new e.Vector3;return function(b,c){var d=c||new e.Vector3,f=b.delta(a),g=this.normal.dot(f);if(0!=g){var h=-(b.start.dot(this.normal)+this.constant)/g;if(!(0>h||h>1))return d.copy(f).multiplyScalar(h).add(b.start)}else if(0==this.distanceToPoint(b.start))return d.copy(b.start)}}(),coplanarPoint:function(a){var b=a||new e.Vector3;return b.copy(this.normal).multiplyScalar(-this.constant)},applyMatrix4:function(){var a=new e.Vector3,b=new e.Vector3,c=new e.Matrix3;return function(d,f){if(!(d instanceof e.Matrix4))return e.onerror("expecting a Matrix4",d);var g=f||c.getNormalMatrix(d),h=a.copy(this.normal).applyMatrix3(g),i=this.coplanarPoint(b);return i.applyMatrix4(d),this.setFromNormalAndCoplanarPoint(h,i),this}}(),translate:function(a){return this.constant=this.constant-a.dot(this.normal),this},equals:function(a){return a.normal.equals(this.normal)&&a.constant==this.constant},clone:function(){return(new e.Plane).copy(this)}},e.Math={PI2:2*Math.PI,DegreeToRadiansFactor:Math.PI/180,RadianToDegreesFactor:180/Math.PI,generateUUID:function(){var a,b="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),c=new Array(36),d=0;return function(){for(var e=0;36>e;e++)8==e||13==e||18==e||23==e?c[e]="-":14==e?c[e]="4":(2>=d&&(d=33554432+16777216*Math.random()|0),a=15&d,d>>=4,c[e]=b[19==e?3&a|8:a]);return c.join("")}}(),clamp:function(a,b,c){return b>a?b:a>c?c:a},clampBottom:function(a,b){return b>a?b:a},mapLinear:function(a,b,c,d,e){return d+(a-b)*(e-d)/(c-b)},smoothstep:function(a,b,c){return b>=a?0:a>=c?1:(a=(a-b)/(c-b),a*a*(3-2*a))},smootherstep:function(a,b,c){return b>=a?0:a>=c?1:(a=(a-b)/(c-b),a*a*a*(a*(6*a-15)+10))},random16:function(){return(65280*Math.random()+255*Math.random())/65535},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},sign:function(a){return 0>a?-1:a>0?1:0},degToRad:function(a){return a*this.DegreeToRadiansFactor},radToDeg:function(a){return a*this.RadianToDegreesFactor},isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a}},e.Spline=function(a){function b(a,b,c,d,e,f,g){var h=.5*(c-a),i=.5*(d-b);return(2*(b-c)+h+i)*g+(-3*(b-c)-2*h-i)*f+h*e+b}this.points=a;var c,d,f,g,h,i,j,k,l,m=[],n={x:0,y:0,z:0};this.initFromArray=function(a){this.points=[];for(var b=0;bthis.points.length-2?this.points.length-1:d+1,m[3]=d>this.points.length-3?this.points.length-1:d+2,i=this.points[m[0]],j=this.points[m[1]],k=this.points[m[2]],l=this.points[m[3]],g=f*f,h=f*g,n.x=b(i.x,j.x,k.x,l.x,f,g,h),n.y=b(i.y,j.y,k.y,l.y,f,g,h),n.z=b(i.z,j.z,k.z,l.z,f,g,h),n},this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;c>a;a++)b=this.points[a],d[a]=[b.x,b.y,b.z];return d},this.getLength=function(a){var b,c,d,f,g=0,h=0,i=0,j=new e.Vector3,k=new e.Vector3,l=[],m=0;for(l[0]=0,a||(a=100),d=this.points.length*a,j.copy(this.points[0]),b=1;d>b;b++)c=b/d,f=this.getPoint(c),k.copy(f),m+=k.distanceTo(j),j.copy(f),g=(this.points.length-1)*c,h=Math.floor(g),h!=i&&(l[h]=m,i=h);return l[l.length]=m,{chunks:l,total:m}},this.reparametrizeByArcLength=function(a){var b,c,d,f,g,h,i,j,k=[],l=new e.Vector3,m=this.getLength();for(k.push(l.copy(this.points[0]).clone()),b=1;bc;c++)d=f+c*(1/i)*(g-f),j=this.getPoint(d),k.push(l.copy(j).clone());k.push(l.copy(this.points[b]).clone())}this.points=k}},e.Triangle=function(a,b,c){this.a=void 0!==a?a:new e.Vector3,this.b=void 0!==b?b:new e.Vector3,this.c=void 0!==c?c:new e.Vector3},e.Triangle.normal=function(){var a=new e.Vector3;return function(b,c,d,f){var g=f||new e.Vector3;g.subVectors(d,c),a.subVectors(b,c),g.cross(a);var h=g.lengthSq();return h>0?g.multiplyScalar(1/Math.sqrt(h)):g.set(0,0,0)}}(),e.Triangle.barycoordFromPoint=function(){var a=new e.Vector3,b=new e.Vector3,c=new e.Vector3;return function(d,f,g,h,i){a.subVectors(h,f),b.subVectors(g,f),c.subVectors(d,f);var j=a.dot(a),k=a.dot(b),l=a.dot(c),m=b.dot(b),n=b.dot(c),o=j*m-k*k,p=i||new e.Vector3;if(0==o)return p.set(-2,-1,-1);var q=1/o,r=(m*l-k*n)*q,s=(j*n-k*l)*q;return p.set(1-r-s,s,r)}}(),e.Triangle.containsPoint=function(){var a=new e.Vector3;return function(b,c,d,f){var g=e.Triangle.barycoordFromPoint(b,c,d,f,a);return g.x>=0&&g.y>=0&&g.x+g.y<=1}}(),e.Triangle.prototype={constructor:e.Triangle,set:function(a,b,c){return this.a.copy(a),this.b.copy(b),this.c.copy(c),this},setFromPointsAndIndices:function(a,b,c,d){return this.a.copy(a[b]),this.b.copy(a[c]),this.c.copy(a[d]),this},copy:function(a){return this.a.copy(a.a),this.b.copy(a.b),this.c.copy(a.c),this},area:function(){var a=new e.Vector3,b=new e.Vector3;return function(){return a.subVectors(this.c,this.b),b.subVectors(this.a,this.b),.5*a.cross(b).length()}}(),midpoint:function(a){var b=a||new e.Vector3;return b.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return e.Triangle.normal(this.a,this.b,this.c,a)},plane:function(a){var b=a||new e.Plane;return b.setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return e.Triangle.barycoordFromPoint(a,this.a,this.b,this.c,b)},containsPoint:function(a){return e.Triangle.containsPoint(a,this.a,this.b,this.c)},equals:function(a){return a.a.equals(this.a)&&a.b.equals(this.b)&&a.c.equals(this.c)},clone:function(){return(new e.Triangle).copy(this)}},e.Vertex=function(a){return e.onerror("THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.")},e.UV=function(a,b){return e.onerror("THREE.UV has been DEPRECATED. Use THREE.Vector2 instead."),new e.Vector2(a,b)},e.Clock=function(a){this.autoStart=void 0!==a?a:!0,this.startTime=0,this.oldTime=0,this.elapsedTime=0,this.running=!1},e.Clock.prototype={constructor:e.Clock,start:function(){this.startTime=void 0!==d.performance&&void 0!==d.performance.now?d.performance.now():Date.now(),this.oldTime=this.startTime,this.running=!0},stop:function(){this.getElapsedTime(),this.running=!1},getElapsedTime:function(){return this.getDelta(),this.elapsedTime},getDelta:function(){var a=0;if(this.autoStart&&!this.running&&this.start(),this.running){var b=void 0!==d.performance&&void 0!==d.performance.now?d.performance.now():Date.now();a=.001*(b-this.oldTime),this.oldTime=b,this.elapsedTime+=a}return a}},e.EventDispatcher=function(){},e.EventDispatcher.prototype={constructor:e.EventDispatcher,apply:function(a){a.addEventListener=e.EventDispatcher.prototype.addEventListener,a.hasEventListener=e.EventDispatcher.prototype.hasEventListener,a.removeEventListener=e.EventDispatcher.prototype.removeEventListener,a.dispatchEvent=e.EventDispatcher.prototype.dispatchEvent},addEventListener:function(a,b){void 0===this._listeners&&(this._listeners={});var c=this._listeners;void 0===c[a]&&(c[a]=[]),-1===c[a].indexOf(b)&&c[a].push(b)},hasEventListener:function(a,b){if(void 0===this._listeners)return!1;var c=this._listeners;return void 0!==c[a]&&-1!==c[a].indexOf(b)},removeEventListener:function(a,b){if(void 0!==this._listeners){var c=this._listeners,d=c[a];if(void 0!==d){var e=d.indexOf(b);-1!==e&&d.splice(e,1)}}},dispatchEvent:function(){var a=[];return function(b){if(void 0!==this._listeners){var c=this._listeners,d=c[b.type];if(void 0!==d){b.target=this;for(var e=d.length,f=0;e>f;f++)a[f]=d[f];for(var f=0;e>f;f++)a[f].call(this,b)}}}}()},function(a){a.Raycaster=function(b,c,d,e){this.ray=new a.Ray(b,c),this.near=d||0,this.far=e||1/0};var b=new a.Sphere,c=new a.Ray,d=(new a.Plane,new a.Vector3,new a.Vector3),e=new a.Matrix4,f=function(a,b){return a.distance-b.distance},g=new a.Vector3,h=new a.Vector3,i=new a.Vector3,j=function(f,k,l){if(f instanceof a.Sprite){d.setFromMatrixPosition(f.matrixWorld);var m=k.ray.distanceToPoint(d);if(m>f.scale.x)return l;l.push({distance:m,point:f.position,face:null,object:f})}else if(f instanceof a.LOD){d.setFromMatrixPosition(f.matrixWorld);var m=k.ray.origin.distanceTo(d);j(f.getObjectForDistance(m),k,l)}else if(f instanceof a.Mesh){var n=f.geometry;if(null===n.boundingSphere&&n.computeBoundingSphere(),b.copy(n.boundingSphere),b.applyMatrix4(f.matrixWorld),k.ray.isIntersectionSphere(b)===!1)return l;if(e.getInverse(f.matrixWorld),c.copy(k.ray).applyMatrix4(e),null!==n.boundingBox&&c.isIntersectionBox(n.boundingBox)===!1)return l;if(n instanceof a.BufferGeometry){var o=f.material;if(void 0===o)return l;var p,q,r,s=n.attributes,t=k.precision;if(void 0!==s.index)for(var u=n.offsets,v=s.index.array,w=s.position.array,x=0,y=u.length;y>x;++x)for(var z=u[x].start,A=u[x].count,B=u[x].index,C=z,D=z+A;D>C;C+=3){if(p=B+v[C],q=B+v[C+1],r=B+v[C+2],g.set(w[3*p],w[3*p+1],w[3*p+2]),h.set(w[3*q],w[3*q+1],w[3*q+2]),i.set(w[3*r],w[3*r+1],w[3*r+2]),o.side===a.BackSide)var E=c.intersectTriangle(i,h,g,!0);else var E=c.intersectTriangle(g,h,i,o.side!==a.DoubleSide);if(null!==E){E.applyMatrix4(f.matrixWorld);var m=k.ray.origin.distanceTo(E);t>m||mk.far||l.push({distance:m,point:E,indices:[p,q,r],face:null,faceIndex:null,object:f})}}else for(var u=n.offsets,w=s.position.array,C=0,D=s.position.array.length;D>C;C+=3){if(p=C,q=C+1,r=C+2,g.set(w[3*p],w[3*p+1],w[3*p+2]),h.set(w[3*q],w[3*q+1],w[3*q+2]),i.set(w[3*r],w[3*r+1],w[3*r+2]),o.side===a.BackSide)var E=c.intersectTriangle(i,h,g,!0);else var E=c.intersectTriangle(g,h,i,o.side!==a.DoubleSide);if(null!==E){E.applyMatrix4(f.matrixWorld);var m=k.ray.origin.distanceTo(E);t>m||mk.far||l.push({distance:m,point:E,indices:[p,q,r],face:null,faceIndex:null,object:f})}}}else if(n instanceof a.Geometry)for(var p,q,r,F=f.material instanceof a.MeshFaceMaterial,G=F===!0?f.material.materials:null,t=k.precision,H=n.vertices,I=0,J=n.faces.length;J>I;I++){var K=n.faces[I],o=F===!0?G[K.materialIndex]:f.material;if(void 0!==o){if(p=H[K.a],q=H[K.b],r=H[K.c],o.morphTargets===!0){var L=n.morphTargets,M=f.morphTargetInfluences;g.set(0,0,0),h.set(0,0,0),i.set(0,0,0);for(var N=0,O=L.length;O>N;N++){var P=M[N];if(0!==P){var Q=L[N].vertices;g.x+=(Q[K.a].x-p.x)*P,g.y+=(Q[K.a].y-p.y)*P,g.z+=(Q[K.a].z-p.z)*P,h.x+=(Q[K.b].x-q.x)*P,h.y+=(Q[K.b].y-q.y)*P,h.z+=(Q[K.b].z-q.z)*P,i.x+=(Q[K.c].x-r.x)*P,i.y+=(Q[K.c].y-r.y)*P,i.z+=(Q[K.c].z-r.z)*P}}g.add(p),h.add(q),i.add(r),p=g,q=h,r=i}if(o.side===a.BackSide)var E=c.intersectTriangle(r,q,p,!0);else var E=c.intersectTriangle(p,q,r,o.side!==a.DoubleSide);if(null!==E){E.applyMatrix4(f.matrixWorld);var m=k.ray.origin.distanceTo(E);t>m||mk.far||l.push({distance:m,point:E,face:K,faceIndex:I,object:f})}}}}else if(f instanceof a.Line){var t=k.linePrecision,R=t*t,n=f.geometry;if(null===n.boundingSphere&&n.computeBoundingSphere(),b.copy(n.boundingSphere),b.applyMatrix4(f.matrixWorld),k.ray.isIntersectionSphere(b)===!1)return l;if(e.getInverse(f.matrixWorld),c.copy(k.ray).applyMatrix4(e),n instanceof a.Geometry)for(var H=n.vertices,S=H.length,T=new a.Vector3,U=new a.Vector3,V=f.type===a.LineStrip?1:2,C=0;S-1>C;C+=V){var W=c.distanceSqToSegment(H[C],H[C+1],U,T);if(!(W>R)){var m=c.origin.distanceTo(U);mk.far||l.push({distance:m,point:T.clone().applyMatrix4(f.matrixWorld),face:null,faceIndex:null,object:f})}}}},k=function(a,b,c){for(var d=a.getDescendants(),e=0,f=d.length;f>e;e++)j(d[e],b,c)};a.Raycaster.prototype.precision=1e-4,a.Raycaster.prototype.linePrecision=1,a.Raycaster.prototype.set=function(a,b){this.ray.set(a,b)},a.Raycaster.prototype.intersectObject=function(a,b){var c=[];return b===!0&&k(a,this,c),j(a,this,c),c.sort(f),c},a.Raycaster.prototype.intersectObjects=function(a,b){for(var c=[],d=0,e=a.length;e>d;d++)j(a[d],this,c),b===!0&&k(a[d],this,c);return c.sort(f),c}}(e),e.Object3D=function(){this.id=e.Object3DIdCount++,this.uuid=e.Math.generateUUID(),this.className="Object3D",this.name="",this.parent=void 0,this.children=[],this.up=new e.Vector3(0,1,0),this.position=new e.Vector3,this._rotation=new e.Euler,this._quaternion=new e.Quaternion,this.scale=new e.Vector3(1,1,1),this._rotation._quaternion=this.quaternion,this._quaternion._euler=this.rotation,this.renderDepth=null,this.rotationAutoUpdate=!0,this.matrix=new e.Matrix4,this.matrixWorld=new e.Matrix4,this.matrixAutoUpdate=!0,this.matrixWorldNeedsUpdate=!0,this.visible=!0,this.castShadow=!1,this.receiveShadow=!1,this.frustumCulled=!0,this.userData={}},e.Object3D.prototype={constructor:e.Object3D,get rotation(){return this._rotation},set rotation(a){this._rotation=a,this._rotation._quaternion=this._quaternion,this._quaternion._euler=this._rotation,this._rotation._updateQuaternion()},get quaternion(){return this._quaternion},set quaternion(a){this._quaternion=a,this._quaternion._euler=this._rotation,this._rotation._quaternion=this._quaternion,this._quaternion._updateEuler()},get eulerOrder(){return e.onwarning("DEPRECATED: Object3D's .eulerOrder has been moved to Object3D's .rotation.order."),this.rotation.order},set eulerOrder(a){e.onwarning("DEPRECATED: Object3D's .eulerOrder has been moved to Object3D's .rotation.order."),this.rotation.order=a},get useQuaternion(){e.onwarning("DEPRECATED: Object3D's .useQuaternion has been removed. The library now uses quaternions by default.")},set useQuaternion(a){e.onwarning("DEPRECATED: Object3D's .useQuaternion has been removed. The library now uses quaternions by default.")},applyMatrix:function(a){this.matrix.multiplyMatrices(a,this.matrix),this.matrix.decompose(this.position,this.quaternion,this.scale)},setRotationFromAxisAngle:function(a,b){this.quaternion.setFromAxisAngle(a,b)},setRotationFromEuler:function(a){this.quaternion.setFromEuler(a,!0)},setRotationFromMatrix:function(a){this.quaternion.setFromRotationMatrix(a)},setRotationFromQuaternion:function(a){this.quaternion.copy(a)},rotateOnAxis:function(){var a=new e.Quaternion;return function(b,c){return a.setFromAxisAngle(b,c),this.quaternion.multiply(a),this}}(),rotateX:function(){var a=new e.Vector3(1,0,0);return function(b){return this.rotateOnAxis(a,b)}}(),rotateY:function(){var a=new e.Vector3(0,1,0);return function(b){return this.rotateOnAxis(a,b)}}(),rotateZ:function(){var a=new e.Vector3(0,0,1);return function(b){return this.rotateOnAxis(a,b)}}(),translateOnAxis:function(){var a=new e.Vector3;return function(b,c){return a.copy(b),a.applyQuaternion(this.quaternion),this.position.add(a.multiplyScalar(c)),this}}(),translate:function(a,b){return e.onwarning("DEPRECATED: Object3D's .translate() has been removed. Use .translateOnAxis( axis, distance ) instead. Note args have been changed."),this.translateOnAxis(b,a)},translateX:function(){var a=new e.Vector3(1,0,0);return function(b){return this.translateOnAxis(a,b)}}(),translateY:function(){var a=new e.Vector3(0,1,0);return function(b){return this.translateOnAxis(a,b)}}(),translateZ:function(){var a=new e.Vector3(0,0,1);return function(b){return this.translateOnAxis(a,b)}}(),localToWorld:function(a){return a.applyMatrix4(this.matrixWorld)},worldToLocal:function(){var a=new e.Matrix4;return function(b){return b.applyMatrix4(a.getInverse(this.matrixWorld))}}(),lookAt:function(){var a=new e.Matrix4;return function(b){a.lookAt(b,this.position,this.up),this.quaternion.setFromRotationMatrix(a)}}(),add:function(a){if(a===this)return void e.onwarning("THREE.Object3D.add: An object can't be added as a child of itself.");if(a instanceof e.Object3D){void 0!==a.parent&&a.parent.remove(a),a.parent=this,a.dispatchEvent({type:"added"}),this.children.push(a);for(var b=this;void 0!==b.parent;)b=b.parent;void 0!==b&&b instanceof e.Scene&&b.__addObject(a)}},remove:function(a){var b=this.children.indexOf(a);if(-1!==b){a.parent=void 0,a.dispatchEvent({type:"removed"}),this.children.splice(b,1);for(var c=this;void 0!==c.parent;)c=c.parent;void 0!==c&&c instanceof e.Scene&&c.__removeObject(a)}},traverse:function(a){a(this);for(var b=0,c=this.children.length;c>b;b++)this.children[b].traverse(a)},getObjectById:function(a,b){for(var c=0,d=this.children.length;d>c;c++){var e=this.children[c];if(e.id===a)return e;if(b===!0&&(e=e.getObjectById(a,b),void 0!==e))return e}},getObjectByName:function(a,b){for(var c=0,d=this.children.length;d>c;c++){var e=this.children[c];if(e.name===a)return e;if(b===!0&&(e=e.getObjectByName(a,b),void 0!==e))return e}},getChildByName:function(a,b){return e.onwarning("DEPRECATED: Object3D's .getChildByName() has been renamed to .getObjectByName()."),this.getObjectByName(a,b)},getDescendants:function(a){void 0===a&&(a=[]),Array.prototype.push.apply(a,this.children);for(var b=0,c=this.children.length;c>b;b++)this.children[b].getDescendants(a);return a},updateMatrix:function(){this.matrix.compose(this.position,this.quaternion,this.scale),this.matrixWorldNeedsUpdate=!0},updateMatrixWorld:function(a){this.matrixAutoUpdate===!0&&this.updateMatrix(),this.matrixWorldNeedsUpdate!==!0&&a!==!0||(void 0===this.parent?this.matrixWorld.copy(this.matrix):this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix),this.matrixWorldNeedsUpdate=!1,a=!0);for(var b=0,c=this.children.length;c>b;b++)this.children[b].updateMatrixWorld(a)},clone:function(a,b){if(void 0===a&&(a=new e.Object3D),void 0===b&&(b=!0),a.name=this.name,a.up.copy(this.up),a.position.copy(this.position),a.quaternion.copy(this.quaternion),a.scale.copy(this.scale),a.renderDepth=this.renderDepth,a.rotationAutoUpdate=this.rotationAutoUpdate,a.matrix.copy(this.matrix),a.matrixWorld.copy(this.matrixWorld),a.matrixAutoUpdate=this.matrixAutoUpdate,a.matrixWorldNeedsUpdate=this.matrixWorldNeedsUpdate,a.visible=this.visible,a.castShadow=this.castShadow,a.receiveShadow=this.receiveShadow,a.frustumCulled=this.frustumCulled,a.userData=JSON.parse(JSON.stringify(this.userData)),b===!0)for(var c=0;c=0&&f>=0&&g>=0&&h>=0?!0:0>e&&0>f||0>g&&0>h?!1:(0>e?c=Math.max(c,e/(e-f)):0>f&&(d=Math.min(d,e/(e-f))),0>g?c=Math.max(c,g/(g-h)):0>h&&(d=Math.min(d,g/(g-h))),c>d?!1:(a.lerp(b,c),b.lerp(a,1-d),!0))}var i,j,k,l,m,n,o,p,q,r,s,t=[],u=0,v=[],w=0,x=[],y=0,z=[],A=0,B=[],C=0,D={objects:[],lights:[],elements:[]},E=new e.Vector3,F=new e.Vector3,G=new e.Vector3,H=new e.Vector3,I=new e.Vector4,J=new e.Box3(new e.Vector3(-1,-1,-1),new e.Vector3(1,1,1)),K=new e.Box3,L=new Array(3),M=(new Array(4),new e.Matrix4),N=new e.Matrix4,O=new e.Matrix4,P=new e.Matrix3,Q=new e.Frustum,R=new e.Vector4,S=new e.Vector4;this.projectVector=function(a,b){return b.matrixWorldInverse.getInverse(b.matrixWorld),N.multiplyMatrices(b.projectionMatrix,b.matrixWorldInverse),a.applyProjection(N)},this.unprojectVector=function(){var a=new e.Matrix4;return function(b,c){return a.getInverse(c.projectionMatrix),N.multiplyMatrices(c.matrixWorld,a),b.applyProjection(N)}}(),this.pickingRay=function(a,b){a.z=-1;var c=new e.Vector3(a.x,a.y,1);return this.unprojectVector(a,b),this.unprojectVector(c,b),c.sub(a).normalize(),new e.Raycaster(a,c)};var T=function(b){if(b.visible!==!1){b instanceof e.Light?D.lights.push(b):(b instanceof e.Mesh||b instanceof e.Line||b instanceof e.Sprite)&&(b.frustumCulled!==!1&&Q.intersectsObject(b)!==!0||(i=a(),i.id=b.id,i.object=b,null!==b.renderDepth?i.z=b.renderDepth:(H.setFromMatrixPosition(b.matrixWorld),H.applyProjection(N),i.z=H.z),D.objects.push(i)));for(var c=0,d=b.children.length;d>c;c++)T(b.children[c])}},U=function(a,b){j=0,D.objects.length=0,D.lights.length=0,T(a),b===!0&&D.objects.sort(g)},V=function(){var a=[],f=null,g=new e.Matrix3,h=function(b){f=b,g.getNormalMatrix(f.matrixWorld),a.length=0},i=function(a){var b=a.position,c=a.positionWorld,d=a.positionScreen;c.copy(b).applyMatrix4(s),d.copy(c).applyMatrix4(N);var e=1/d.w;d.x*=e,d.y*=e,d.z*=e,a.visible=d.x>=-1&&d.x<=1&&d.y>=-1&&d.y<=1&&d.z>=-1&&d.z<=1},j=function(a,c,d){k=b(),k.position.set(a,c,d),i(k)},l=function(b,c,d){a.push(b,c,d)},n=function(a,b,c){return L[0]=a.positionScreen,L[1]=b.positionScreen,L[2]=c.positionScreen,a.visible===!0||b.visible===!0||c.visible===!0||J.isIntersectionBox(K.setFromPoints(L))?(c.positionScreen.x-a.positionScreen.x)*(b.positionScreen.y-a.positionScreen.y)-(c.positionScreen.y-a.positionScreen.y)*(b.positionScreen.x-a.positionScreen.x)<0:!1},p=function(a,b){var c=v[a],e=v[b];o=d(),o.id=f.id,o.v1.copy(c),o.v2.copy(e),o.z=(c.positionScreen.z+e.positionScreen.z)/2,o.material=f.material,D.elements.push(o)},q=function(b,d,e){var h=v[b],i=v[d],j=v[e];if(n(h,i,j)===!0){m=c(),m.id=f.id,m.v1.copy(h),m.v2.copy(i),m.v3.copy(j),m.z=(h.positionScreen.z+i.positionScreen.z+j.positionScreen.z)/3;for(var k=0;3>k;k++){var l=3*arguments[k],o=m.vertexNormalsModel[k];o.set(a[l+0],a[l+1],a[l+2]),o.applyMatrix3(g).normalize()}m.vertexNormalsLength=3,m.material=f.material,D.elements.push(m)}};return{setObject:h,projectVertex:i,checkTriangleVisibility:n,pushVertex:j,pushNormal:l,pushLine:p,pushTriangle:q}},W=new V;this.projectScene=function(a,i,j,k){var t,u,w,x,y,z,A,B,C,H;n=0,p=0,r=0,D.elements.length=0,a.autoUpdate===!0&&a.updateMatrixWorld(),void 0===i.parent&&i.updateMatrixWorld(),M.copy(i.matrixWorldInverse.getInverse(i.matrixWorld)),N.multiplyMatrices(i.projectionMatrix,M),Q.setFromMatrix(N),U(a,j);for(var J=0,K=D.objects.length;K>J;J++)if(t=D.objects[J].object,u=t.geometry,W.setObject(t),s=t.matrixWorld,l=0,t instanceof e.Mesh){if(u instanceof e.BufferGeometry){var L=u.attributes,T=u.offsets;if(void 0===L.position)continue;for(var V=L.position.array,X=0,Y=V.length;Y>X;X+=3)W.pushVertex(V[X],V[X+1],V[X+2]);for(var Z=L.normal.array,X=0,Y=Z.length;Y>X;X+=3)W.pushNormal(Z[X],Z[X+1],Z[X+2]);if(void 0!==L.index){var $=L.index.array;if(T.length>0)for(var J=0;JX;X+=3)W.pushTriangle($[X]+aa,$[X+1]+aa,$[X+2]+aa);else for(var X=0,Y=$.length;Y>X;X+=3)W.pushTriangle($[X],$[X+1],$[X+2])}else for(var X=0,Y=V.length/3;Y>X;X+=3)W.pushTriangle(X,X+1,X+2)}else if(u instanceof e.Geometry){w=u.vertices,x=u.faces,A=u.faceVertexUvs,P.getNormalMatrix(s),C=t.material instanceof e.MeshFaceMaterial,H=C===!0?t.material:null;for(var ba=0,ca=w.length;ca>ba;ba++){var da=w[ba];W.pushVertex(da.x,da.y,da.z)}for(var ea=0,fa=x.length;fa>ea;ea++){y=x[ea];var ga=C===!0?H.materials[y.materialIndex]:t.material;if(void 0!==ga){var ha=ga.side,ia=v[y.a],ja=v[y.b],ka=v[y.c];if(ga.morphTargets===!0){var la=u.morphTargets,ma=t.morphTargetInfluences,na=ia.position,oa=ja.position,pa=ka.position;E.set(0,0,0),F.set(0,0,0),G.set(0,0,0);for(var qa=0,ra=la.length;ra>qa;qa++){var sa=ma[qa];if(0!==sa){var ta=la[qa].vertices;E.x+=(ta[y.a].x-na.x)*sa,E.y+=(ta[y.a].y-na.y)*sa,E.z+=(ta[y.a].z-na.z)*sa,F.x+=(ta[y.b].x-oa.x)*sa,F.y+=(ta[y.b].y-oa.y)*sa,F.z+=(ta[y.b].z-oa.z)*sa,G.x+=(ta[y.c].x-pa.x)*sa,G.y+=(ta[y.c].y-pa.y)*sa,G.z+=(ta[y.c].z-pa.z)*sa}}ia.position.add(E),ja.position.add(F),ka.position.add(G),W.projectVertex(ia),W.projectVertex(ja),W.projectVertex(ka)}var ua=W.checkTriangleVisibility(ia,ja,ka);if(!(ua===!1&&ha===e.FrontSide||ua===!0&&ha===e.BackSide)){m=c(),m.id=t.id,m.v1.copy(ia),m.v2.copy(ja),m.v3.copy(ka),m.normalModel.copy(y.normal),ua!==!1||ha!==e.BackSide&&ha!==e.DoubleSide||m.normalModel.negate(),m.normalModel.applyMatrix3(P).normalize(),m.centroidModel.copy(y.centroid).applyMatrix4(s),z=y.vertexNormals;for(var va=0,wa=Math.min(z.length,3);wa>va;va++){var xa=m.vertexNormalsModel[va];xa.copy(z[va]),ua!==!1||ha!==e.BackSide&&ha!==e.DoubleSide||xa.negate(),xa.applyMatrix3(P).normalize()}m.vertexNormalsLength=z.length;for(var ya=0,za=Math.min(A.length,3);za>ya;ya++)if(B=A[ya][ea],void 0!==B)for(var Aa=0,Ba=B.length;Ba>Aa;Aa++)m.uvs[ya][Aa]=B[Aa];m.color=y.color,m.material=ga,m.z=(ia.positionScreen.z+ja.positionScreen.z+ka.positionScreen.z)/3,D.elements.push(m)}}}}}else if(t instanceof e.Line){if(u instanceof e.BufferGeometry){var L=u.attributes;if(void 0!==L.position){for(var V=L.position.array,X=0,Y=V.length;Y>X;X+=3)W.pushVertex(V[X],V[X+1],V[X+2]);if(void 0!==L.index)for(var $=L.index.array,X=0,Y=$.length;Y>X;X+=2)W.pushLine($[X],$[X+1]);else for(var X=0,Y=V.length/3-1;Y>X;X++)W.pushLine(X,X+1)}}else if(u instanceof e.Geometry){if(O.multiplyMatrices(N,s),w=t.geometry.vertices,0===w.length)continue;ia=b(),ia.positionScreen.copy(w[0]).applyMatrix4(O);for(var Ca=t.type===e.LinePieces?2:1,ba=1,ca=w.length;ca>ba;ba++)ia=b(),ia.positionScreen.copy(w[ba]).applyMatrix4(O),(ba+1)%Ca>0||(ja=v[l-2],R.copy(ia.positionScreen),S.copy(ja.positionScreen),h(R,S)===!0&&(R.multiplyScalar(1/R.w),S.multiplyScalar(1/S.w),o=d(),o.id=t.id,o.v1.positionScreen.copy(R),o.v2.positionScreen.copy(S),o.z=Math.max(R.z,S.z),o.material=t.material,t.material.vertexColors===e.VertexColors&&(o.vertexColors[0].copy(t.geometry.colors[ba]),o.vertexColors[1].copy(t.geometry.colors[ba-1])),D.elements.push(o)))}}else if(t instanceof e.Sprite){I.set(s.elements[12],s.elements[13],s.elements[14],1),I.applyMatrix4(N);var Da=1/I.w;I.z*=Da,I.z>=-1&&I.z<=1&&(q=f(),q.id=t.id,q.x=I.x*Da,q.y=I.y*Da,q.z=I.z,q.object=t,q.rotation=t.rotation,q.scale.x=t.scale.x*Math.abs(q.x-(I.x+i.projectionMatrix.elements[0])/(I.w+i.projectionMatrix.elements[12])),q.scale.y=t.scale.y*Math.abs(q.y-(I.y+i.projectionMatrix.elements[5])/(I.w+i.projectionMatrix.elements[13])),q.material=t.material,D.elements.push(q))}return k===!0&&D.elements.sort(g),D}},e.Face3=function(a,b,c,d,f,g){this.a=a,this.b=b,this.c=c,this.normal=d instanceof e.Vector3?d:new e.Vector3,this.vertexNormals=d instanceof Array?d:[],this.color=f instanceof e.Color?f:new e.Color,this.vertexColors=f instanceof Array?f:[],this.vertexTangents=[],this.materialIndex=void 0!==g?g:0,this.centroid=new e.Vector3},e.Face3.prototype={constructor:e.Face3,clone:function(){var a=new e.Face3(this.a,this.b,this.c);a.normal.copy(this.normal),a.color.copy(this.color),a.centroid.copy(this.centroid),a.materialIndex=this.materialIndex;var b,c;for(b=0,c=this.vertexNormals.length;c>b;b++)a.vertexNormals[b]=this.vertexNormals[b].clone();for(b=0,c=this.vertexColors.length;c>b;b++)a.vertexColors[b]=this.vertexColors[b].clone();for(b=0,c=this.vertexTangents.length;c>b;b++)a.vertexTangents[b]=this.vertexTangents[b].clone();return a}},e.Face4=function(a,b,c,d,f,g,h){return e.onwarning("THREE.Face4 has been removed. A THREE.Face3 will be created instead."),new e.Face3(a,b,c,f,g,h)},e.BufferGeometry=function(){this.id=e.GeometryIdCount++,this.uuid=e.Math.generateUUID(),this.className="BufferGeometry",this.name="",this.attributes={},this.offsets=[],this.boundingBox=null,this.boundingSphere=null},e.BufferGeometry.prototype={constructor:e.BufferGeometry,addAttribute:function(a,b,c,d){return this.attributes[a]={array:new b(c*d),itemSize:d},this.attributes[a]},applyMatrix:function(a){var b=this.attributes.position;void 0!==b&&(a.multiplyVector3Array(b.array),b.needsUpdate=!0);var c=this.attributes.normal;if(void 0!==c){var d=(new e.Matrix3).getNormalMatrix(a);d.multiplyVector3Array(c.array),c.needsUpdate=!0}},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new e.Box3);var a=this.attributes.position.array;if(a){var b=this.boundingBox;a.length>=3&&(b.min.x=b.max.x=a[0],b.min.y=b.max.y=a[1],b.min.z=b.max.z=a[2]);for(var c=3,d=a.length;d>c;c+=3){var f=a[c],g=a[c+1],h=a[c+2];fb.max.x&&(b.max.x=f),gb.max.y&&(b.max.y=g),hb.max.z&&(b.max.z=h)}}void 0!==a&&0!==a.length||(this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0))},computeBoundingSphere:function(){var a=new e.Box3,b=new e.Vector3;return function(){null===this.boundingSphere&&(this.boundingSphere=new e.Sphere);var c=this.attributes.position.array;if(c){a.makeEmpty();for(var d=this.boundingSphere.center,f=0,g=c.length;g>f;f+=3)b.set(c[f],c[f+1],c[f+2]),a.addPoint(b);a.center(d);for(var h=0,f=0,g=c.length;g>f;f+=3)b.set(c[f],c[f+1],c[f+2]),h=Math.max(h,d.distanceToSquared(b));this.boundingSphere.radius=Math.sqrt(h)}}}(),computeVertexNormals:function(){if(this.attributes.position){var a,b,c,d,f=this.attributes.position.array.length;if(void 0===this.attributes.normal)this.attributes.normal={itemSize:3,array:new Float32Array(f)};else for(a=0,b=this.attributes.normal.array.length;b>a;a++)this.attributes.normal.array[a]=0;var g,h,i,j,k,l,m=this.attributes.position.array,n=this.attributes.normal.array,o=new e.Vector3,p=new e.Vector3,q=new e.Vector3,r=new e.Vector3,s=new e.Vector3;if(this.attributes.index){var t=this.attributes.index.array,u=this.offsets;for(c=0,d=u.length;d>c;++c){var v=u[c].start,w=u[c].count,x=u[c].index;for(a=v,b=v+w;b>a;a+=3)g=x+t[a],h=x+t[a+1],i=x+t[a+2],j=m[3*g],k=m[3*g+1],l=m[3*g+2],o.set(j,k,l),j=m[3*h],k=m[3*h+1],l=m[3*h+2],p.set(j,k,l),j=m[3*i],k=m[3*i+1],l=m[3*i+2],q.set(j,k,l),r.subVectors(q,p),s.subVectors(o,p),r.cross(s),n[3*g]+=r.x,n[3*g+1]+=r.y,n[3*g+2]+=r.z,n[3*h]+=r.x,n[3*h+1]+=r.y,n[3*h+2]+=r.z,n[3*i]+=r.x,n[3*i+1]+=r.y,n[3*i+2]+=r.z}}else for(a=0,b=m.length;b>a;a+=9)j=m[a],k=m[a+1],l=m[a+2],o.set(j,k,l),j=m[a+3],k=m[a+4],l=m[a+5],p.set(j,k,l),j=m[a+6],k=m[a+7],l=m[a+8],q.set(j,k,l),r.subVectors(q,p),s.subVectors(o,p),r.cross(s),n[a]=r.x,n[a+1]=r.y,n[a+2]=r.z,n[a+3]=r.x,n[a+4]=r.y,n[a+5]=r.z,n[a+6]=r.x,n[a+7]=r.y,n[a+8]=r.z;this.normalizeNormals(),this.normalsNeedUpdate=!0}},normalizeNormals:function(){for(var a,b,c,d,e=this.attributes.normal.array,f=0,g=e.length;g>f;f+=3)a=e[f],b=e[f+1],c=e[f+2],d=1/Math.sqrt(a*a+b*b+c*c),e[f]*=d,e[f+1]*=d,e[f+2]*=d},computeTangents:function(){function a(a,b,c){n=d[3*a],o=d[3*a+1],p=d[3*a+2],q=d[3*b],r=d[3*b+1],s=d[3*b+2],t=d[3*c],u=d[3*c+1],v=d[3*c+2],w=g[2*a],x=g[2*a+1],y=g[2*b],z=g[2*b+1],A=g[2*c],B=g[2*c+1],C=q-n,D=t-n,E=r-o,F=u-o,G=s-p,H=v-p,I=y-w,J=A-w,K=z-x,L=B-x,M=1/(I*L-J*K),U.set((L*C-K*D)*M,(L*E-K*F)*M,(L*G-K*H)*M),V.set((I*D-J*C)*M,(I*F-J*E)*M,(I*H-J*G)*M),k[a].add(U),k[b].add(U),k[c].add(U),l[a].add(V),l[b].add(V),l[c].add(V)}function b(a){da.x=f[3*a],da.y=f[3*a+1],da.z=f[3*a+2],ea.copy(da),_=k[a],ba.copy(_),ba.sub(da.multiplyScalar(da.dot(_))).normalize(),ca.crossVectors(ea,_),aa=ca.dot(l[a]),$=0>aa?-1:1,j[4*a]=ba.x,j[4*a+1]=ba.y,j[4*a+2]=ba.z,j[4*a+3]=$}if(void 0===this.attributes.index||void 0===this.attributes.position||void 0===this.attributes.normal||void 0===this.attributes.uv)return void e.onwarning("Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");var c=this.attributes.index.array,d=this.attributes.position.array,f=this.attributes.normal.array,g=this.attributes.uv.array,h=d.length/3;if(void 0===this.attributes.tangent){var i=4*h;this.attributes.tangent={itemSize:4,array:new Float32Array(i)}}for(var j=this.attributes.tangent.array,k=[],l=[],m=0;h>m;m++)k[m]=new e.Vector3, +l[m]=new e.Vector3;var n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U=new e.Vector3,V=new e.Vector3,W=this.offsets;for(P=0,Q=W.length;Q>P;++P){var X=W[P].start,Y=W[P].count,Z=W[P].index;for(N=X,O=X+Y;O>N;N+=3)R=Z+c[N],S=Z+c[N+1],T=Z+c[N+2],a(R,S,T)}var $,_,aa,ba=new e.Vector3,ca=new e.Vector3,da=new e.Vector3,ea=new e.Vector3;for(P=0,Q=W.length;Q>P;++P){var X=W[P].start,Y=W[P].count,Z=W[P].index;for(N=X,O=X+Y;O>N;N+=3)R=Z+c[N],S=Z+c[N+1],T=Z+c[N+2],b(R),b(S),b(T)}},computeOffsets:function(a){var b=a;void 0===a&&(b=65535);for(var c=(Date.now(),this.attributes.index.array),d=this.attributes.position.array,e=(d.length/3,c.length/3),f=new Uint16Array(c.length),g=0,h=0,i=[{start:0,count:0,index:0}],j=i[0],k=0,l=0,m=new Int32Array(6),n=new Int32Array(d.length),o=new Int32Array(d.length),p=0;pq;q++){l=0;for(var r=0;3>r;r++){var s=c[3*q+r];-1==n[s]?(m[2*r]=s,m[2*r+1]=-1,l++):n[s]j.index+b){var u={start:g,count:0,index:h};i.push(u),j=u;for(var v=0;6>v;v+=2){var w=m[v+1];w>-1&&wv;v+=2){var s=m[v],w=m[v+1];-1===w&&(w=h++),n[s]=w,o[w]=s,f[g++]=w-j.index,j.count++}}return this.reorderBuffers(f,o,h),this.offsets=i,i},reorderBuffers:function(a,b,c){var d={},e=[Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];for(var f in this.attributes)if("index"!=f)for(var g=this.attributes[f].array,h=0,i=e.length;i>h;h++){var j=e[h];if(g instanceof j){d[f]=new j(this.attributes[f].itemSize*c);break}}for(var k=0;c>k;k++){var l=b[k];for(var f in this.attributes)if("index"!=f)for(var m=this.attributes[f].array,n=this.attributes[f].itemSize,o=d[f],p=0;n>p;p++)o[k*n+p]=m[l*n+p]}this.attributes.index.array=a;for(var f in this.attributes)"index"!=f&&(this.attributes[f].array=d[f],this.attributes[f].numItems=this.attributes[f].itemSize*c)},clone:function(){var a=new e.BufferGeometry,b=[Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];for(var c in this.attributes){for(var d=this.attributes[c],f=d.array,g={itemSize:d.itemSize,array:null},h=0,i=b.length;i>h;h++){var j=b[h];if(f instanceof j){g.array=new j(f);break}}a.attributes[c]=g}for(var h=0,i=this.offsets.length;i>h;h++){var k=this.offsets[h];a.offsets.push({start:k.start,index:k.index,count:k.count})}return a},dispose:function(){this.dispatchEvent({type:"dispose"})}},e.EventDispatcher.prototype.apply(e.BufferGeometry.prototype),e.Geometry=function(){this.id=e.GeometryIdCount++,this.uuid=e.Math.generateUUID(),this.className="Geometry",this.name="",this.vertices=[],this.colors=[],this.faces=[],this.faceVertexUvs=[[]],this.morphTargets=[],this.morphColors=[],this.morphNormals=[],this.skinWeights=[],this.skinIndices=[],this.lineDistances=[],this.boundingBox=null,this.boundingSphere=null,this.hasTangents=!0,this.dynamic=!0,this.verticesNeedUpdate=!1,this.elementsNeedUpdate=!1,this.uvsNeedUpdate=!1,this.normalsNeedUpdate=!1,this.tangentsNeedUpdate=!1,this.colorsNeedUpdate=!1,this.lineDistancesNeedUpdate=!1,this.buffersNeedUpdate=!1},e.Geometry.prototype={constructor:e.Geometry,applyMatrix:function(a){for(var b=(new e.Matrix3).getNormalMatrix(a),c=0,d=this.vertices.length;d>c;c++){var f=this.vertices[c];f.applyMatrix4(a)}for(var c=0,d=this.faces.length;d>c;c++){var g=this.faces[c];g.normal.applyMatrix3(b).normalize();for(var h=0,i=g.vertexNormals.length;i>h;h++)g.vertexNormals[h].applyMatrix3(b).normalize();g.centroid.applyMatrix4(a)}this.boundingBox instanceof e.Box3&&this.computeBoundingBox(),this.boundingSphere instanceof e.Sphere&&this.computeBoundingSphere()},computeCentroids:function(){var a,b,c;for(a=0,b=this.faces.length;b>a;a++)c=this.faces[a],c.centroid.set(0,0,0),c.centroid.add(this.vertices[c.a]),c.centroid.add(this.vertices[c.b]),c.centroid.add(this.vertices[c.c]),c.centroid.divideScalar(3)},computeFaceNormals:function(){for(var a=new e.Vector3,b=new e.Vector3,c=0,d=this.faces.length;d>c;c++){var f=this.faces[c],g=this.vertices[f.a],h=this.vertices[f.b],i=this.vertices[f.c];a.subVectors(i,h),b.subVectors(g,h),a.cross(b),a.normalize(),f.normal.copy(a)}},computeVertexNormals:function(a){var b,c,d,f,g,h;for(h=new Array(this.vertices.length),b=0,c=this.vertices.length;c>b;b++)h[b]=new e.Vector3;if(a){var i,j,k,l=new e.Vector3,m=new e.Vector3;new e.Vector3,new e.Vector3,new e.Vector3;for(d=0,f=this.faces.length;f>d;d++)g=this.faces[d],i=this.vertices[g.a],j=this.vertices[g.b],k=this.vertices[g.c],l.subVectors(k,j),m.subVectors(i,j),l.cross(m),h[g.a].add(l),h[g.b].add(l),h[g.c].add(l)}else for(d=0,f=this.faces.length;f>d;d++)g=this.faces[d],h[g.a].add(g.normal),h[g.b].add(g.normal),h[g.c].add(g.normal);for(b=0,c=this.vertices.length;c>b;b++)h[b].normalize();for(d=0,f=this.faces.length;f>d;d++)g=this.faces[d],g.vertexNormals[0]=h[g.a].clone(),g.vertexNormals[1]=h[g.b].clone(),g.vertexNormals[2]=h[g.c].clone()},computeMorphNormals:function(){var a,b,c,d,f;for(c=0,d=this.faces.length;d>c;c++)for(f=this.faces[c],f.__originalFaceNormal?f.__originalFaceNormal.copy(f.normal):f.__originalFaceNormal=f.normal.clone(),f.__originalVertexNormals||(f.__originalVertexNormals=[]),a=0,b=f.vertexNormals.length;b>a;a++)f.__originalVertexNormals[a]?f.__originalVertexNormals[a].copy(f.vertexNormals[a]):f.__originalVertexNormals[a]=f.vertexNormals[a].clone();var g=new e.Geometry;for(g.faces=this.faces,a=0,b=this.morphTargets.length;b>a;a++){if(!this.morphNormals[a]){this.morphNormals[a]={},this.morphNormals[a].faceNormals=[],this.morphNormals[a].vertexNormals=[];var h,i,j=this.morphNormals[a].faceNormals,k=this.morphNormals[a].vertexNormals;for(c=0,d=this.faces.length;d>c;c++)f=this.faces[c],h=new e.Vector3,i={a:new e.Vector3,b:new e.Vector3,c:new e.Vector3},j.push(h),k.push(i)}var l=this.morphNormals[a];g.vertices=this.morphTargets[a].vertices,g.computeFaceNormals(),g.computeVertexNormals();var h,i;for(c=0,d=this.faces.length;d>c;c++)f=this.faces[c],h=l.faceNormals[c],i=l.vertexNormals[c],h.copy(f.normal),i.a.copy(f.vertexNormals[0]),i.b.copy(f.vertexNormals[1]),i.c.copy(f.vertexNormals[2])}for(c=0,d=this.faces.length;d>c;c++)f=this.faces[c],f.normal=f.__originalFaceNormal,f.vertexNormals=f.__originalVertexNormals},computeTangents:function(){function a(a,b,c,d,e,f,g){k=a.vertices[b],l=a.vertices[c],m=a.vertices[d],n=j[e],o=j[f],p=j[g],q=l.x-k.x,r=m.x-k.x,s=l.y-k.y,t=m.y-k.y,u=l.z-k.z,v=m.z-k.z,w=o.x-n.x,x=p.x-n.x,y=o.y-n.y,z=p.y-n.y,A=1/(w*z-x*y),G.set((z*q-y*r)*A,(z*s-y*t)*A,(z*u-y*v)*A),H.set((w*r-x*q)*A,(w*t-x*s)*A,(w*v-x*u)*A),E[b].add(G),E[c].add(G),E[d].add(G),F[b].add(H),F[c].add(H),F[d].add(H)}var b,c,d,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E=[],F=[],G=new e.Vector3,H=new e.Vector3,I=new e.Vector3,J=new e.Vector3,K=new e.Vector3;for(d=0,f=this.vertices.length;f>d;d++)E[d]=new e.Vector3,F[d]=new e.Vector3;for(b=0,c=this.faces.length;c>b;b++)i=this.faces[b],j=this.faceVertexUvs[0][b],a(this,i.a,i.b,i.c,0,1,2);var L=["a","b","c","d"];for(b=0,c=this.faces.length;c>b;b++)for(i=this.faces[b],g=0;gC?-1:1,i.vertexTangents[g]=new e.Vector4(I.x,I.y,I.z,D);this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;d>c;c++)c>0&&(a+=b[c].distanceTo(b[c-1])),this.lineDistances[c]=a},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new e.Box3),this.boundingBox.setFromPoints(this.vertices)},computeBoundingSphere:function(){null===this.boundingSphere&&(this.boundingSphere=new e.Sphere),this.boundingSphere.setFromPoints(this.vertices)},mergeVertices:function(){var a,b,c,d,e,f,g,h,i={},j=[],k=[],l=4,m=Math.pow(10,l);for(c=0,d=this.vertices.length;d>c;c++)a=this.vertices[c],b=Math.round(a.x*m)+"_"+Math.round(a.y*m)+"_"+Math.round(a.z*m),void 0===i[b]?(i[b]=c,j.push(this.vertices[c]),k[c]=j.length-1):k[c]=k[i[b]];var n=[];for(c=0,d=this.faces.length;d>c;c++){e=this.faces[c],e.a=k[e.a],e.b=k[e.b],e.c=k[e.c],f=[e.a,e.b,e.c];for(var o=-1,p=0;3>p;p++)if(f[p]==f[(p+1)%3]){o=p,n.push(c);break}}for(c=n.length-1;c>=0;c--){var q=n[c];for(this.faces.splice(q,1),g=0,h=this.faceVertexUvs.length;h>g;g++)this.faceVertexUvs[g].splice(q,1)}var r=this.vertices.length-j.length;return this.vertices=j,r},makeGroups:function(){var a=0;return function(b){var c,d,e,f,g,h={},i=this.morphTargets.length,j=this.morphNormals.length;for(this.geometryGroups={},c=0,d=this.faces.length;d>c;c++)e=this.faces[c],f=b?e.materialIndex:0,f in h||(h[f]={hash:f,counter:0}),g=h[f].hash+"_"+h[f].counter,g in this.geometryGroups||(this.geometryGroups[g]={faces3:[],materialIndex:f,vertices:0,numMorphTargets:i,numMorphNormals:j}),this.geometryGroups[g].vertices+3>65535&&(h[f].counter+=1,g=h[f].hash+"_"+h[f].counter,g in this.geometryGroups||(this.geometryGroups[g]={faces3:[],materialIndex:f,vertices:0,numMorphTargets:i,numMorphNormals:j})),this.geometryGroups[g].faces3.push(c),this.geometryGroups[g].vertices+=3;this.geometryGroupsList=[];for(var k in this.geometryGroups)this.geometryGroups[k].id=a++,this.geometryGroupsList.push(this.geometryGroups[k])}}(),clone:function(){for(var a=new e.Geometry,b=this.vertices,c=0,d=b.length;d>c;c++)a.vertices.push(b[c].clone());for(var f=this.faces,c=0,d=f.length;d>c;c++)a.faces.push(f[c].clone());for(var g=this.faceVertexUvs[0],c=0,d=g.length;d>c;c++){for(var h=g[c],i=[],j=0,k=h.length;k>j;j++)i.push(new e.Vector2(h[j].x,h[j].y));a.faceVertexUvs[0].push(i)}return a.morphTargets=this.morphTargets.slice(0),a.morphColors=this.morphColors.slice(0),a.morphNormals=this.morphNormals.slice(0),a.skinWeights=this.skinWeights.slice(0),a.skinIndices=this.skinIndices.slice(0),a.lineDistances=this.lineDistances.slice(0),this.boundingBox&&(a.boundingBox=this.boundingBox.clone()),this.boundingSphere&&(a.boundingSphere=this.boundingSphere.clone()),a.hasTangents=this.hasTangents,a.dynamic=this.dynamic,a},dispose:function(){this.dispatchEvent({type:"dispose"})}},e.EventDispatcher.prototype.apply(e.Geometry.prototype),e.GeometryIdCount=0,e.Geometry2=function(a){e.BufferGeometry.call(this),this.className="Geometry2",this.vertices=this.addAttribute("position",Float32Array,a,3).array,this.normals=this.addAttribute("normal",Float32Array,a,3).array,this.uvs=this.addAttribute("uv",Float32Array,a,2).array,this.boundingBox=null,this.boundingSphere=null},e.Geometry2.prototype=Object.create(e.BufferGeometry.prototype),e.Camera=function(){e.Object3D.call(this),this.matrixWorldInverse=new e.Matrix4,this.projectionMatrix=new e.Matrix4,this.normalizedViewport={x:0,y:0,width:1,height:1}},e.Camera.prototype=Object.create(e.Object3D.prototype),e.Camera.prototype.lookAt=function(){var a=new e.Matrix4;return function(b){a.lookAt(this.position,b,this.up),this.quaternion.setFromRotationMatrix(a)}}(),e.Camera.prototype.clone=function(a){return void 0===a&&(a=new e.Camera),e.Object3D.prototype.clone.call(this,a),a.matrixWorldInverse.copy(this.matrixWorldInverse),a.projectionMatrix.copy(this.projectionMatrix),a.normalizedViewport={x:this.normalizedViewport.x,y:this.normalizedViewport.y,width:this.normalizedViewport.width,height:this.normalizedViewport.height},a},e.OrthographicCamera=function(a,b,c,d,f,g){e.Camera.call(this),this.left=a,this.right=b,this.top=c,this.bottom=d,this.near=void 0!==f?f:.1,this.far=void 0!==g?g:2e3,this.updateProjectionMatrix()},e.OrthographicCamera.prototype=Object.create(e.Camera.prototype),e.OrthographicCamera.prototype.updateProjectionMatrix=function(){this.projectionMatrix.makeOrthographic(this.left,this.right,this.top,this.bottom,this.near,this.far);var a=new e.Matrix4;a.elements[0]*=this.normalizedViewport.width,a.elements[1]*=this.normalizedViewport.height,a.elements[12]+=this.normalizedViewport.x,a.elements[13]+=this.normalizedViewport.y,this.projectionMatrix=a.multiply(this.projectionMatrix)},e.OrthographicCamera.prototype.clone=function(){var a=new e.OrthographicCamera;return e.Camera.prototype.clone.call(this,a),a.left=this.left,a.right=this.right,a.top=this.top,a.bottom=this.bottom,a.near=this.near,a.far=this.far,a},e.PerspectiveCamera=function(a,b,c,d,f,g){e.Camera.call(this),this.fov=void 0!==a?a:50,this.aspect=void 0!==b?b:1,this.near=void 0!==c?c:.1,this.far=void 0!==d?d:2e3,this.filmSize=void 0!==f?f:new e.Vector2(1,1),this.filmOffset=void 0!==g?g:new e.Vector2(0,0),this.updateProjectionMatrix()},e.PerspectiveCamera.prototype=Object.create(e.Camera.prototype),e.PerspectiveCamera.prototype.setLens=function(a,b){void 0===b&&(b=24),this.fov=2*e.Math.radToDeg(Math.atan(b/(2*a))),this.updateProjectionMatrix()},e.PerspectiveCamera.prototype.setViewOffset=function(a,b,c,d,e,f){this.fullWidth=a,this.fullHeight=b,this.x=c,this.y=d,this.width=e,this.height=f,this.updateProjectionMatrix()},e.PerspectiveCamera.prototype.updateProjectionMatrix=function(){if(this.fullWidth){var a=this.fullWidth/this.fullHeight,b=Math.tan(e.Math.degToRad(.5*this.fov))*this.near,c=-b,d=a*c,f=a*b,g=Math.abs(f-d),h=Math.abs(b-c);this.projectionMatrix.makeFrustum(d+this.x*g/this.fullWidth,d+(this.x+this.width)*g/this.fullWidth,b-(this.y+this.height)*h/this.fullHeight,b-this.y*h/this.fullHeight,this.near,this.far,this.filmOffset,this.filmSize)}else this.projectionMatrix.makePerspective(this.fov,this.aspect,this.near,this.far,this.filmOffset,this.filmSize);var i=new e.Matrix4;i.elements[0]*=this.normalizedViewport.width,i.elements[1]*=this.normalizedViewport.height,i.elements[12]+=this.normalizedViewport.x,i.elements[13]+=this.normalizedViewport.y,this.projectionMatrix=i.multiply(this.projectionMatrix)},e.PerspectiveCamera.prototype.clone=function(){var a=new e.PerspectiveCamera;return e.Camera.prototype.clone.call(this,a),a.fov=this.fov,a.aspect=this.aspect,a.near=this.near,a.far=this.far,a.filmSize=this.filmSize,a.filmOffset=this.filmOffset,a},e.Light=function(a){e.Object3D.call(this),this.color=new e.Color(a)},e.Light.prototype=Object.create(e.Object3D.prototype),e.Light.prototype.clone=function(a){return void 0===a&&(a=new e.Light),e.Object3D.prototype.clone.call(this,a),a.color.copy(this.color),a},e.AmbientLight=function(a){e.Light.call(this,a)},e.AmbientLight.prototype=Object.create(e.Light.prototype),e.AmbientLight.prototype.clone=function(){var a=new e.AmbientLight;return e.Light.prototype.clone.call(this,a),a},e.AreaLight=function(a,b,c,d,f){e.Light.call(this,a),this.position.set(0,1,0),this.target=new e.Object3D,this.intensity=void 0!==b?b:1,this.distance=void 0!==c?c:0,this.decayExponent=void 0!==d?d:0,this.physicalFalloff=void 0!==f?f:!1,this.width=1,this.height=1},e.AreaLight.prototype=Object.create(e.Light.prototype),e.AreaLight.prototype.clone=function(){var a=new e.AreaLight;return e.Light.prototype.clone.call(this,a),a.target=this.target.clone(),a.intensity=this.intensity,a.distance=this.distance,a.decayExponent=this.decayExponent,a.physicalFalloff=this.physicalFalloff,a.width=this.width,a.height=this.height,a},e.DirectionalLight=function(a,b){e.Light.call(this,a),this.position.set(0,1,0),this.target=new e.Object3D,this.intensity=void 0!==b?b:1,this.castShadow=!1,this.onlyShadow=!1,this.shadowCameraNear=50,this.shadowCameraFar=5e3,this.shadowCameraLeft=-500,this.shadowCameraRight=500,this.shadowCameraTop=500,this.shadowCameraBottom=-500,this.shadowCameraVisible=!1,this.shadowBias=0,this.shadowDarkness=.5,this.shadowMapWidth=512,this.shadowMapHeight=512,this.shadowCascade=!1,this.shadowCascadeOffset=new e.Vector3(0,0,-1e3),this.shadowCascadeCount=2,this.shadowCascadeBias=[0,0,0],this.shadowCascadeWidth=[512,512,512],this.shadowCascadeHeight=[512,512,512],this.shadowCascadeNearZ=[-1,.99,.998],this.shadowCascadeFarZ=[.99,.998,1],this.shadowCascadeArray=[],this.shadowMap=null,this.shadowMapSize=null,this.shadowCamera=null,this.shadowMatrix=null},e.DirectionalLight.prototype=Object.create(e.Light.prototype),e.DirectionalLight.prototype.clone=function(){var a=new e.DirectionalLight;return e.Light.prototype.clone.call(this,a),a.target=this.target.clone(),a.intensity=this.intensity,a.castShadow=this.castShadow,a.onlyShadow=this.onlyShadow,a},e.HemisphereLight=function(a,b,c){e.Light.call(this,a),this.position.set(0,100,0),this.groundColor=new e.Color(b),this.intensity=void 0!==c?c:1},e.HemisphereLight.prototype=Object.create(e.Light.prototype),e.HemisphereLight.prototype.clone=function(){var a=new e.HemisphereLight;return e.Light.prototype.clone.call(this,a),a.groundColor.copy(this.groundColor),a.intensity=this.intensity,a},e.PointLight=function(a,b,c,d,f){e.Light.call(this,a),this.intensity=void 0!==b?b:1,this.distance=void 0!==c?c:0,this.decayExponent=void 0!==d?d:0,this.physicalFalloff=void 0!==f?f:!1},e.PointLight.prototype=Object.create(e.Light.prototype),e.PointLight.prototype.clone=function(){var a=new e.PointLight;return e.Light.prototype.clone.call(this,a),a.intensity=this.intensity,a.distance=this.distance,a.decayExponent=this.decayExponent,a.physicalFalloff=this.physicalFalloff,a},e.SpotLight=function(a,b,c,d,f,g,h){e.Light.call(this,a),this.position.set(0,1,0),this.target=new e.Object3D,this.intensity=void 0!==b?b:1,this.distance=void 0!==c?c:0,this.decayExponent=void 0!==g?g:0,this.physicalFalloff=void 0!==h?h:!1,this.angle=void 0!==d?d:Math.PI/3,this.exponent=void 0!==f?f:10,this.castShadow=!1,this.onlyShadow=!1,this.shadowCameraNear=50,this.shadowCameraFar=5e3,this.shadowCameraFov=50,this.shadowCameraVisible=!1,this.shadowBias=0,this.shadowDarkness=.5,this.shadowMapWidth=512,this.shadowMapHeight=512,this.shadowMap=null,this.shadowMapSize=null,this.shadowCamera=null,this.shadowMatrix=null},e.SpotLight.prototype=Object.create(e.Light.prototype),e.SpotLight.prototype.clone=function(){var a=new e.SpotLight;return e.Light.prototype.clone.call(this,a),a.target=this.target.clone(),a.intensity=this.intensity,a.distance=this.distance,a.angle=this.angle,a.exponent=this.exponent,a.decayExponent=this.decayExponent,a.physicalFalloff=this.physicalFalloff,a.castShadow=this.castShadow,a.onlyShadow=this.onlyShadow,a},e.Loader=function(a){this.showStatus=a,this.statusDomElement=a?e.Loader.prototype.addStatusElement():null,this.onLoadStart=function(){},this.onLoadProgress=function(){},this.onLoadComplete=function(){}},e.Loader.prototype={constructor:e.Loader,crossOrigin:void 0,addStatusElement:function(){var a=document.createElement("div");return a.style.position="absolute",a.style.right="0px",a.style.top="0px",a.style.fontSize="0.8em",a.style.textAlign="left",a.style.background="rgba(0,0,0,0.25)",a.style.color="#fff",a.style.width="120px",a.style.padding="0.5em 0.5em 0.5em 0.5em",a.style.zIndex=1e3,a.innerHTML="Loading ...",a},updateProgress:function(a){var b="Loaded ";b+=a.total?(100*a.loaded/a.total).toFixed(0)+"%":(a.loaded/1e3).toFixed(2)+" KB",this.statusDomElement.innerHTML=b},extractUrlBase:function(a){var b=a.split("/");return 1===b.length?"./":(b.pop(),b.join("/")+"/")},initMaterials:function(a,b){for(var c=[],d=0;db;b++){var d=a[b];if(d instanceof e.ShaderMaterial)return!0}return!1},createMaterial:function(a,b){function c(a){var b=Math.log(a)/Math.LN2;return Math.floor(b)==b}function d(a){var b=Math.log(a)/Math.LN2;return Math.pow(2,Math.round(b))}function f(a,b){var e=new Image;e.onload=function(){if(c(this.width)&&c(this.height))a.image=this;else{var b=d(this.width),e=d(this.height);a.image.width=b,a.image.height=e,a.image.getContext("2d").drawImage(this,0,0,b,e)}a.needsUpdate=!0},void 0!==i.crossOrigin&&(e.crossOrigin=i.crossOrigin),e.src=b}function g(a,c,d,g,h,i,j){var k=/\.dds$/i.test(d),l=b+d;if(k){var m=e.ImageUtils.loadCompressedTexture(l);a[c]=m}else{var m=document.createElement("canvas");a[c]=new e.Texture(m)}if(a[c].sourceFile=d,g&&(a[c].repeat.set(g[0],g[1]),1!==g[0]&&(a[c].wrapS=e.RepeatWrapping),1!==g[1]&&(a[c].wrapT=e.RepeatWrapping)),h&&a[c].offset.set(h[0],h[1]),i){var n={repeat:e.RepeatWrapping,mirror:e.MirroredRepeatWrapping};void 0!==n[i[0]]&&(a[c].wrapS=n[i[0]]),void 0!==n[i[1]]&&(a[c].wrapT=n[i[1]])}j&&(a[c].anisotropy=j),k||f(a[c],l)}function h(a){return(255*a[0]<<16)+(255*a[1]<<8)+255*a[2]}var i=this,j="MeshLambertMaterial",k={color:15658734,opacity:1,map:null,lightMap:null,normalMap:null,bumpMap:null,wireframe:!1};if(a.shading){var l=a.shading.toLowerCase();"phong"===l?j="MeshPhongMaterial":"basic"===l?j="MeshBasicMaterial":"physical"===l&&(j="MeshPhysicalMaterial")}if(void 0!==a.blending&&void 0!==e[a.blending]&&(k.blending=e[a.blending]),(void 0!==a.transparent||a.opacity<1)&&(k.transparent=a.transparent),void 0!==a.depthTest&&(k.depthTest=a.depthTest),void 0!==a.depthWrite&&(k.depthWrite=a.depthWrite),void 0!==a.visible&&(k.visible=a.visible),void 0!==a.flipSided&&(k.side=e.BackSide),void 0!==a.doubleSided&&(k.side=e.DoubleSide),void 0!==a.wireframe&&(k.wireframe=a.wireframe),void 0!==a.vertexColors&&("face"===a.vertexColors?k.vertexColors=e.FaceColors:a.vertexColors&&(k.vertexColors=e.VertexColors)),a.colorDiffuse?k.color=h(a.colorDiffuse):a.DbgColor&&(k.color=a.DbgColor),a.colorSpecular&&(k.specular=h(a.colorSpecular)),a.colorAmbient&&(k.ambient=h(a.colorAmbient)),a.transparency&&(k.opacity=a.transparency),a.specularCoef&&(k.shininess=a.specularCoef),a.mapDiffuse&&b&&g(k,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap,a.mapDiffuseAnisotropy),a.mapLight&&b&&g(k,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy),a.mapBump&&b&&g(k,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy),a.mapNormal&&b&&g(k,"normalMap",a.mapNormal,a.mapNormalRepeat,a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy),a.mapSpecular&&b&&g(k,"specularMap",a.mapSpecular,a.mapSpecularRepeat,a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy),a.mapBumpScale&&(k.bumpScale=a.mapBumpScale),a.mapNormal){var m=e.ShaderLib.normalmap,n=e.UniformsUtils.clone(m.uniforms);n.tNormal.value=k.normalMap,a.mapNormalFactor&&n.uNormalScale.value.set(a.mapNormalFactor,a.mapNormalFactor),k.map&&(n.tDiffuse.value=k.map,n.enableDiffuse.value=!0),k.specularMap&&(n.tSpecular.value=k.specularMap,n.enableSpecular.value=!0),k.lightMap&&(n.tAO.value=k.lightMap,n.enableAO.value=!0),n.diffuse.value.setHex(k.color),n.specular.value.setHex(k.specular),n.ambient.value.setHex(k.ambient),n.shininess.value=k.shininess,void 0!==k.opacity&&(n.opacity.value=k.opacity);var o={fragmentShader:m.fragmentShader,vertexShader:m.vertexShader,uniforms:n,lights:!0,fog:!0},p=new e.ShaderMaterial(o);k.transparent&&(p.transparent=!0)}else var p=new e[j](k);return void 0!==a.DbgName&&(p.name=a.DbgName),p}},e.XHRLoader=function(a){this.manager=void 0!==a?a:e.DefaultLoadingManager},e.XHRLoader.prototype={constructor:e.XHRLoader,load:function(a,b,c,d){var e=this,f=new XMLHttpRequest;void 0!==b&&f.addEventListener("load",function(c){b(c.target.responseText),e.manager.itemEnd(a)},!1),void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1),void 0!==d&&f.addEventListener("error",function(a){d(a)},!1),void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin),f.open("GET",a,!0),f.send(null),e.manager.itemStart(a)},setCrossOrigin:function(a){this.crossOrigin=a}},e.ImageLoader=function(a){this.manager=void 0!==a?a:e.DefaultLoadingManager},e.ImageLoader.prototype={constructor:e.ImageLoader,load:function(a,b,c,d){var e=this,f=document.createElement("img");return void 0!==b&&f.addEventListener("load",function(c){e.manager.itemEnd(a),b(this)},!1),void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1),void 0!==d&&f.addEventListener("error",function(a){d(a)},!1),void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin),f.src=a,e.manager.itemStart(a),f},setCrossOrigin:function(a){this.crossOrigin=a}},e.JSONLoader=function(a){e.Loader.call(this,a),this.withCredentials=!1},e.JSONLoader.prototype=Object.create(e.Loader.prototype),e.JSONLoader.prototype.load=function(a,b,c){c=c&&"string"==typeof c?c:this.extractUrlBase(a),this.onLoadStart(),this.loadAjaxJSON(this,a,b,c)},e.JSONLoader.prototype.loadAjaxJSON=function(a,b,c,d,f){var g=new XMLHttpRequest,h=0;g.onreadystatechange=function(){if(g.readyState===g.DONE)if(200===g.status||0===g.status){if(g.responseText){var i=JSON.parse(g.responseText);if("scene"===i.metadata.type)return void e.onerror('THREE.JSONLoader: "'+b+'" seems to be a Scene. Use THREE.SceneLoader instead.');var j=a.parse(i,d);c(j.geometry,j.materials)}else e.onerror('THREE.JSONLoader: "'+b+'" seems to be unreachable or the file is empty.');a.onLoadComplete()}else e.onerror("THREE.JSONLoader: Couldn't load \""+b+'" ('+g.status+")");else g.readyState===g.LOADING?f&&(0===h&&(h=g.getResponseHeader("Content-Length")),f({total:h,loaded:g.responseText.length})):g.readyState===g.HEADERS_RECEIVED&&void 0!==f&&(h=g.getResponseHeader("Content-Length"))},g.open("GET",b,!0),g.withCredentials=this.withCredentials,g.send(null)},e.JSONLoader.prototype.parse=function(a,b){function c(b){function c(a,b){return a&1<d;d++)g.faceVertexUvs[d]=[]}for(i=0,j=H.length;j>i;)w=new e.Vector3,w.x=H[i++]*b,w.y=H[i++]*b,w.z=H[i++]*b,g.vertices.push(w);for(i=0,j=G.length;j>i;)if(o=G[i++],p=c(o,0),q=c(o,1),r=c(o,3),s=c(o,4),t=c(o,5),u=c(o,6),v=c(o,7),p){if(y=new e.Face3,y.a=G[i],y.b=G[i+1],y.c=G[i+3],z=new e.Face3,z.a=G[i+1],z.b=G[i+2],z.c=G[i+3],i+=4,q&&(n=G[i++],y.materialIndex=n,z.materialIndex=n),h=g.faces.length,r)for(d=0;K>d;d++)for(C=a.uvs[d],g.faceVertexUvs[d][h]=[],g.faceVertexUvs[d][h+1]=[],f=0;4>f;f++)m=G[i++],E=C[2*m],F=C[2*m+1],D=new e.Vector2(E,F),2!==f&&g.faceVertexUvs[d][h].push(D),0!==f&&g.faceVertexUvs[d][h+1].push(D);if(s&&(l=3*G[i++],y.normal.set(I[l++],I[l++],I[l]),z.normal.copy(y.normal)),t)for(d=0;4>d;d++)l=3*G[i++],B=new e.Vector3(I[l++],I[l++],I[l]),2!==d&&y.vertexNormals.push(B),0!==d&&z.vertexNormals.push(B);if(u&&(k=G[i++],A=J[k],y.color.setHex(A),z.color.setHex(A)),v)for(d=0;4>d;d++)k=G[i++],A=J[k],2!==d&&y.vertexColors.push(new e.Color(A)),0!==d&&z.vertexColors.push(new e.Color(A));g.faces.push(y),g.faces.push(z)}else{if(x=new e.Face3,x.a=G[i++],x.b=G[i++],x.c=G[i++],q&&(n=G[i++],x.materialIndex=n),h=g.faces.length,r)for(d=0;K>d;d++)for(C=a.uvs[d],g.faceVertexUvs[d][h]=[],f=0;3>f;f++)m=G[i++],E=C[2*m],F=C[2*m+1],D=new e.Vector2(E,F),g.faceVertexUvs[d][h].push(D);if(s&&(l=3*G[i++],x.normal.set(I[l++],I[l++],I[l])),t)for(d=0;3>d;d++)l=3*G[i++],B=new e.Vector3(I[l++],I[l++],I[l]),x.vertexNormals.push(B);if(u&&(k=G[i++],x.color.setHex(J[k])),v)for(d=0;3>d;d++)k=G[i++],x.vertexColors.push(new e.Color(J[k]));g.faces.push(x)}}function d(){if(a.skinWeights)for(var b=0,c=a.skinWeights.length;c>b;b+=2){var d=a.skinWeights[b],f=a.skinWeights[b+1],h=0,i=0;g.skinWeights.push(new e.Vector4(d,f,h,i))}if(a.skinIndices)for(var b=0,c=a.skinIndices.length;c>b;b+=2){var j=a.skinIndices[b],k=a.skinIndices[b+1],l=0,m=0;g.skinIndices.push(new e.Vector4(j,k,l,m))}g.bones=a.bones,g.bones&&g.bones.length>0&&(g.skinWeights.length!==g.skinIndices.length||g.skinIndices.length!==g.vertices.length)&&e.onwarning("When skinning, number of vertices ("+g.vertices.length+"), skinIndices ("+g.skinIndices.length+"), and skinWeights ("+g.skinWeights.length+") should match."),g.animation=a.animation,g.animations=a.animations}function f(b){if(void 0!==a.morphTargets){var c,d,f,h,i,j;for(c=0,d=a.morphTargets.length;d>c;c++)for(g.morphTargets[c]={},g.morphTargets[c].name=a.morphTargets[c].name,g.morphTargets[c].vertices=[],i=g.morphTargets[c].vertices,j=a.morphTargets[c].vertices,f=0,h=j.length;h>f;f+=3){var k=new e.Vector3;k.x=j[f]*b,k.y=j[f+1]*b,k.z=j[f+2]*b,i.push(k)}}if(void 0!==a.morphColors){var c,d,l,m,n,o,p;for(c=0,d=a.morphColors.length;d>c;c++)for(g.morphColors[c]={},g.morphColors[c].name=a.morphColors[c].name,g.morphColors[c].colors=[],n=g.morphColors[c].colors,o=a.morphColors[c].colors,l=0,m=o.length;m>l;l+=3)p=new e.Color(16755200),p.setRGB(o[l],o[l+1],o[l+2]),n.push(p)}}var g=new e.Geometry,h=void 0!==a.scale?1/a.scale:1;if(c(h),d(),f(h),g.computeCentroids(),g.computeFaceNormals(),g.computeBoundingSphere(),void 0===a.materials)return{geometry:g};var i=this.initMaterials(a.materials,b);return this.needsTangents(i)&&g.computeTangents(),{geometry:g,materials:i}},e.LoadingManager=function(a,b,c){var d=this,e=0,f=0;this.onLoad=a,this.onProgress=b,this.onError=c,this.itemStart=function(a){f++},this.itemEnd=function(a){e++,void 0!==d.onProgress&&d.onProgress(a,e,f),e===f&&void 0!==d.onLoad&&d.onLoad()}},e.DefaultLoadingManager=new e.LoadingManager,e.BufferGeometryLoader=function(a){this.manager=void 0!==a?a:e.DefaultLoadingManager},e.BufferGeometryLoader.prototype={constructor:e.BufferGeometryLoader,load:function(a,b,c,d){var f=this,g=new e.XHRLoader;g.setCrossOrigin(this.crossOrigin),g.load(a,function(a){b(f.parse(JSON.parse(a)))})},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=new e.BufferGeometry,c=a.attributes,f=a.offsets,g=a.boundingSphere;for(var h in c){var i=c[h];b.attributes[h]={itemSize:i.itemSize,array:new d[i.type](i.array)}}return void 0!==f&&(b.offsets=JSON.parse(JSON.stringify(f))),void 0!==g&&(b.boundingSphere=new e.Sphere((new e.Vector3).fromArray(void 0!==g.center?g.center:[0,0,0]),g.radius)),b}},e.Geometry2Loader=function(a){this.manager=void 0!==a?a:e.DefaultLoadingManager},e.Geometry2Loader.prototype={constructor:e.Geometry2Loader,load:function(a,b,c,d){var f=this,g=new e.XHRLoader;g.setCrossOrigin(this.crossOrigin),g.load(a,function(a){b(f.parse(JSON.parse(a)))})},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=new e.Geometry2(a.vertices.length/3),c=["vertices","normals","uvs"],d=a.boundingSphere;for(var f in c){var g=c[f];b[g].set(a[g])}return void 0!==d&&(b.boundingSphere=new e.Sphere((new e.Vector3).fromArray(void 0!==d.center?d.center:[0,0,0]),d.radius)),b}},e.MaterialLoader=function(a){this.manager=void 0!==a?a:e.DefaultLoadingManager},e.MaterialLoader.prototype={constructor:e.MaterialLoader,load:function(a,b,c,d){var f=this,g=new e.XHRLoader;g.setCrossOrigin(this.crossOrigin),g.load(a,function(a){b(f.parse(JSON.parse(a)))})},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=new e[a.type];if(void 0!==a.color&&b.color.setHex(a.color),void 0!==a.ambient&&b.ambient.setHex(a.ambient),void 0!==a.emissive&&b.emissive.setHex(a.emissive),void 0!==a.specular&&b.specular.setHex(a.specular),void 0!==a.falloff&&(b.falloff=a.falloff),void 0!==a.falloffColor&&b.falloffColor.setHex(a.falloffColor),void 0!==a.roughness&&(b.roughness=a.roughness),void 0!==a.metallic&&(b.metallic=a.metallic),void 0!==a.clearCoat&&(b.clearCoat=a.clearCoat),void 0!==a.clearCoatRoughness&&(b.clearCoatRoughness=a.clearCoatRoughness),void 0!==a.anisotropy&&(b.anisotropy=a.anisotropy),void 0!==a.anisotropyRotation&&(b.anisotropyRotation=a.anisotropyRotation),void 0!==a.translucency&&b.translucency.setHex(a.translucency),void 0!==a.translucencyNormalAlpha&&(b.translucencyNormalAlpha=a.translucencyNormalAlpha),void 0!==a.translucencyNormalPower&&(b.translucencyNormalPower=a.translucencyNormalPower),void 0!==a.translucencyViewAlpha&&(b.translucencyViewAlpha=a.translucencyViewAlpha),void 0!==a.translucencyViewPower&&(b.translucencyViewPower=a.translucencyViewPower),void 0!==a.shininess&&(b.shininess=a.shininess),void 0!==a.vertexColors&&(b.vertexColors=a.vertexColors),void 0!==a.blending&&(b.blending=a.blending),void 0!==a.side&&(b.side=a.side),void 0!==a.opacity&&(b.opacity=a.opacity),void 0!==a.transparent&&(b.transparent=a.transparent),void 0!==a.wireframe&&(b.wireframe=a.wireframe),void 0!==a.materials)for(var c=0,d=a.materials.length;d>c;c++)b.materials.push(this.parse(a.materials[c])); +return b}},e.ObjectLoader=function(a){this.manager=void 0!==a?a:e.DefaultLoadingManager},e.ObjectLoader.prototype={constructor:e.ObjectLoader,load:function(a,b,c,d){var f=this,g=new e.XHRLoader(f.manager);g.setCrossOrigin(this.crossOrigin),g.load(a,function(a){b(f.parse(JSON.parse(a)))})},setCrossOrigin:function(a){this.crossOrigin=a},parse:function(a){var b=this.parseGeometries(a.geometries),c=this.parseMaterials(a.materials),d=this.parseObject(a.object,b,c);return d},parseGeometries:function(a){var b={};if(void 0!==a)for(var c=new e.JSONLoader,d=new e.Geometry2Loader,f=new e.BufferGeometryLoader,g=0,h=a.length;h>g;g++){var i,j=a[g];switch(j.type){case"PlaneGeometry":i=new e.PlaneGeometry(j.width,j.height,j.widthSegments,j.heightSegments);break;case"BoxGeometry":case"CubeGeometry":i=new e.BoxGeometry(j.width,j.height,j.depth,j.widthSegments,j.heightSegments,j.depthSegments);break;case"CircleGeometry":i=new e.CircleGeometry(j.radius,j.segments);break;case"CylinderGeometry":i=new e.CylinderGeometry(j.radiusTop,j.radiusBottom,j.height,j.radialSegments,j.heightSegments,j.openEnded);break;case"SphereGeometry":i=new e.SphereGeometry(j.radius,j.widthSegments,j.heightSegments,j.phiStart,j.phiLength,j.thetaStart,j.thetaLength);break;case"IcosahedronGeometry":i=new e.IcosahedronGeometry(j.radius,j.detail);break;case"TorusGeometry":i=new e.TorusGeometry(j.radius,j.tube,j.radialSegments,j.tubularSegments,j.arc);break;case"TorusKnotGeometry":i=new e.TorusKnotGeometry(j.radius,j.tube,j.radialSegments,j.tubularSegments,j.p,j.q,j.heightScale);break;case"BufferGeometry":i=f.parse(j.data);break;case"Geometry2":i=d.parse(j.data);break;case"Geometry":i=c.parse(j.data).geometry}i.uuid=j.uuid,void 0!==j.name&&(i.name=j.name),b[j.uuid]=i}return b},parseMaterials:function(a){var b={};if(void 0!==a)for(var c=new e.MaterialLoader,d=0,f=a.length;f>d;d++){var g=a[d],h=c.parse(g);h.uuid=g.uuid,void 0!==g.name&&(h.name=g.name),b[g.uuid]=h}return b},parseObject:function(){var a=new e.Matrix4;return function(b,c,d){var f;switch(b.type){case"Scene":f=new e.Scene;break;case"PerspectiveCamera":f=new e.PerspectiveCamera(b.fov,b.aspect,b.near,b.far);break;case"OrthographicCamera":f=new e.OrthographicCamera(b.left,b.right,b.top,b.bottom,b.near,b.far);break;case"AmbientLight":f=new e.AmbientLight(b.color);break;case"DirectionalLight":f=new e.DirectionalLight(b.color,b.intensity);break;case"PointLight":f=new e.PointLight(b.color,b.intensity,b.distance,b.decay,b.physicalFalloff);break;case"SpotLight":f=new e.SpotLight(b.color,b.intensity,b.distance,b.angle,b.exponent,b.decay,b.physicalFalloff);break;case"HemisphereLight":f=new e.HemisphereLight(b.color,b.groundColor,b.intensity);break;case"AreaLight":f=new e.AreaLight(b.color,b.intensity,b.distance,b.decayExponent,b.decay,b.physicalFalloff),f.width=b.width||1,f.height=b.height||1;break;case"Mesh":var g=c[b.geometry],h=d[b.material];void 0===g&&e.onerror("THREE.ObjectLoader: Undefined geometry "+b.geometry),void 0===h&&e.onerror("THREE.ObjectLoader: Undefined material "+b.material),f=new e.Mesh(g,h);break;case"Sprite":var h=d[b.material];void 0===h&&e.onerror("THREE.ObjectLoader: Undefined material "+b.material),f=new e.Sprite(h);break;default:f=new e.Object3D}if(f.uuid=b.uuid,void 0!==b.name&&(f.name=b.name),void 0!==b.matrix?(a.fromArray(b.matrix),a.decompose(f.position,f.quaternion,f.scale)):(void 0!==b.position&&f.position.fromArray(b.position),void 0!==b.rotation&&f.rotation.fromArray(b.rotation),void 0!==b.scale&&f.scale.fromArray(b.scale)),void 0!==b.visible&&(f.visible=b.visible),void 0!==b.userData&&(f.userData=b.userData),void 0!==b.children)for(var i in b.children)f.add(this.parseObject(b.children[i],c,d));return f}}()},e.SceneLoader=function(){this.onLoadStart=function(){},this.onLoadProgress=function(){},this.onLoadComplete=function(){},this.callbackSync=function(){},this.callbackProgress=function(){},this.geometryHandlers={},this.hierarchyHandlers={},this.addGeometryHandler("ascii",e.JSONLoader)},e.SceneLoader.prototype={constructor:e.SceneLoader,load:function(a,b,c,d){var f=this,g=new e.XHRLoader(f.manager);g.setCrossOrigin(this.crossOrigin),g.load(a,function(c){f.parse(JSON.parse(c),b,a)})},setCrossOrigin:function(a){this.crossOrigin=a},addGeometryHandler:function(a,b){this.geometryHandlers[a]={loaderClass:b}},addHierarchyHandler:function(a,b){this.hierarchyHandlers[a]={loaderClass:b}},parse:function(a,b,c){function d(a,b){return"relativeToHTML"==b?a:C+a}function f(){g(A.scene,E.objects)}function g(a,b){var c,f,h,i,j;for(var l in b){var m=A.objects[l],n=b[l];if(void 0===m){if(n.type&&n.type in B.hierarchyHandlers){if(void 0===n.loading){var o={type:1,url:1,material:1,position:1,rotation:1,scale:1,visible:1,children:1,userData:1,skin:1,morph:1,mirroredLoop:1,duration:1},s={};for(var t in n)t in o||(s[t]=n[t]);q=A.materials[n.material],n.loading=!0;var u=B.hierarchyHandlers[n.type].loaderObject;u.options?u.load(d(n.url,E.urlBaseType),k(l,a,q,n)):u.load(d(n.url,E.urlBaseType),k(l,a,q,n),s)}}else if(void 0!==n.geometry){if(p=A.geometries[n.geometry]){var w=!1;if(q=A.materials[n.material],w=q instanceof e.ShaderMaterial,f=n.position,h=n.rotation,i=n.scale,c=n.matrix,j=n.quaternion,n.material||(q=new e.MeshFaceMaterial(A.face_materials[n.geometry])),q instanceof e.MeshFaceMaterial&&0===q.materials.length&&(q=new e.MeshFaceMaterial(A.face_materials[n.geometry])),q instanceof e.MeshFaceMaterial)for(var x=0;xba;ba++)aa[ba]=d(Z.url[ba],E.urlBaseType);var ca=/\.dds$/i.test(aa[0]);t=ca?e.ImageUtils.loadCompressedTextureCube(aa,Z.mapping,N(_)):e.ImageUtils.loadTextureCube(aa,Z.mapping,N(_))}else{var ca=/\.dds$/i.test(Z.url),da=d(Z.url,E.urlBaseType),ea=N(1);if(t=ca?e.ImageUtils.loadCompressedTexture(da,Z.mapping,ea):e.ImageUtils.loadTexture(da,Z.mapping,ea),void 0!==e[Z.minFilter]&&(t.minFilter=e[Z.minFilter]),void 0!==e[Z.magFilter]&&(t.magFilter=e[Z.magFilter]),Z.anisotropy&&(t.anisotropy=Z.anisotropy),Z.repeat&&(t.repeat.set(Z.repeat[0],Z.repeat[1]),1!==Z.repeat[0]&&(t.wrapS=e.RepeatWrapping),1!==Z.repeat[1]&&(t.wrapT=e.RepeatWrapping)),Z.offset&&t.offset.set(Z.offset[0],Z.offset[1]),Z.wrap){var fa={repeat:e.RepeatWrapping,mirror:e.MirroredRepeatWrapping};void 0!==fa[Z.wrap[0]]&&(t.wrapS=fa[Z.wrap[0]]),void 0!==fa[Z.wrap[1]]&&(t.wrapT=fa[Z.wrap[1]])}}A.textures[Y]=t}var ga,ha,ia;for(ga in E.materials){ha=E.materials[ga];for(ia in ha.parameters)if("envMap"===ia||"map"===ia||"lightMap"===ia||"bumpMap"===ia)ha.parameters[ia]=A.textures[ha.parameters[ia]];else if("shading"===ia)ha.parameters[ia]="flat"===ha.parameters[ia]?e.FlatShading:e.SmoothShading;else if("side"===ia)"double"==ha.parameters[ia]?ha.parameters[ia]=e.DoubleSide:"back"==ha.parameters[ia]?ha.parameters[ia]=e.BackSide:ha.parameters[ia]=e.FrontSide;else if("blending"===ia)ha.parameters[ia]=ha.parameters[ia]in e?e[ha.parameters[ia]]:e.NormalBlending;else if("combine"===ia)ha.parameters[ia]=ha.parameters[ia]in e?e[ha.parameters[ia]]:e.MultiplyOperation;else if("vertexColors"===ia)"face"==ha.parameters[ia]?ha.parameters[ia]=e.FaceColors:ha.parameters[ia]&&(ha.parameters[ia]=e.VertexColors);else if("wrapRGB"===ia){var ja=ha.parameters[ia];ha.parameters[ia]=new e.Vector3(ja[0],ja[1],ja[2])}if(void 0!==ha.parameters.opacity&&ha.parameters.opacity<1&&(ha.parameters.transparent=!0),ha.parameters.normalMap){var ka=e.ShaderLib.normalmap,la=e.UniformsUtils.clone(ka.uniforms),ma=ha.parameters.color,na=ha.parameters.specular,oa=ha.parameters.ambient,pa=ha.parameters.shininess;la.tNormal.value=A.textures[ha.parameters.normalMap],ha.parameters.normalScale&&la.uNormalScale.value.set(ha.parameters.normalScale[0],ha.parameters.normalScale[1]),ha.parameters.map&&(la.tDiffuse.value=ha.parameters.map,la.enableDiffuse.value=!0),ha.parameters.envMap&&(la.tCube.value=ha.parameters.envMap,la.enableReflection.value=!0,la.reflectivity.value=ha.parameters.reflectivity),ha.parameters.lightMap&&(la.tAO.value=ha.parameters.lightMap,la.enableAO.value=!0),ha.parameters.specularMap&&(la.tSpecular.value=A.textures[ha.parameters.specularMap],la.enableSpecular.value=!0),ha.parameters.displacementMap&&(la.tDisplacement.value=A.textures[ha.parameters.displacementMap],la.enableDisplacement.value=!0,la.uDisplacementBias.value=ha.parameters.displacementBias,la.uDisplacementScale.value=ha.parameters.displacementScale),la.diffuse.value.setHex(ma),la.specular.value.setHex(na),la.ambient.value.setHex(oa),la.shininess.value=pa,ha.parameters.opacity&&(la.opacity.value=ha.parameters.opacity);var qa={fragmentShader:ka.fragmentShader,vertexShader:ka.vertexShader,uniforms:la,lights:!0,fog:!0};q=new e.ShaderMaterial(qa)}else q=new e[ha.type](ha.parameters);q.name=ga,A.materials[ga]=q}for(ga in E.materials)if(ha=E.materials[ga],ha.parameters.materials){for(var ra=[],ba=0;ba0){this.morphTargetBase=-1,this.morphTargetForcedOrder=[],this.morphTargetInfluences=[],this.morphTargetDictionary={};for(var a=0,b=this.geometry.morphTargets.length;b>a;a++)this.morphTargetInfluences.push(0),this.morphTargetDictionary[this.geometry.morphTargets[a].name]=a}},e.Mesh.prototype.getMorphTargetIndexByName=function(a){return void 0!==this.morphTargetDictionary[a]?this.morphTargetDictionary[a]:(e.onwarning("THREE.Mesh.getMorphTargetIndexByName: morph target "+a+" does not exist. Returning 0."),0)},e.Mesh.prototype.clone=function(a){return void 0===a&&(a=new e.Mesh(this.geometry,this.material)),e.Object3D.prototype.clone.call(this,a),a},e.Bone=function(a){e.Object3D.call(this),this.skin=a,this.skinMatrix=new e.Matrix4},e.Bone.prototype=Object.create(e.Object3D.prototype),e.Bone.prototype.update=function(a,b){this.matrixAutoUpdate&&(b|=this.updateMatrix()),(b||this.matrixWorldNeedsUpdate)&&(a?this.skinMatrix.multiplyMatrices(a,this.matrix):this.skinMatrix.copy(this.matrix),this.matrixWorldNeedsUpdate=!1,b=!0);var c,d=this.children.length;for(c=0;d>c;c++)this.children[c].update(this.skinMatrix,b)},e.SkinnedMesh=function(a,b,c){e.Mesh.call(this,a,b),this.useVertexTexture=void 0!==c?c:!0,this.identityMatrix=new e.Matrix4,this.bones=[],this.boneMatrices=[];var d,f,g,h,i,j;if(this.geometry&&void 0!==this.geometry.bones){for(d=0;d256?64:k>64?32:k>16?16:8,this.boneTextureWidth=l,this.boneTextureHeight=l,this.boneMatrices=new Float32Array(this.boneTextureWidth*this.boneTextureHeight*4),this.boneTexture=new e.DataTexture(this.boneMatrices,this.boneTextureWidth,this.boneTextureHeight,e.RGBAFormat,e.FloatType),this.boneTexture.minFilter=e.NearestFilter,this.boneTexture.magFilter=e.NearestFilter,this.boneTexture.generateMipmaps=!1,this.boneTexture.flipY=!1}else this.boneMatrices=new Float32Array(16*k);this.pose()}},e.SkinnedMesh.prototype=Object.create(e.Mesh.prototype),e.SkinnedMesh.prototype.addBone=function(a){return void 0===a&&(a=new e.Bone(this)),this.bones.push(a),a},e.SkinnedMesh.prototype.updateMatrixWorld=function(){var a=new e.Matrix4;return function(b){this.matrixAutoUpdate&&this.updateMatrix(),(this.matrixWorldNeedsUpdate||b)&&(this.parent?this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix):this.matrixWorld.copy(this.matrix),this.matrixWorldNeedsUpdate=!1,b=!0);for(var c=0,d=this.children.length;d>c;c++){var f=this.children[c];f instanceof e.Bone?f.update(this.identityMatrix,!1):f.updateMatrixWorld(!0)}if(void 0==this.boneInverses){this.boneInverses=[];for(var g=0,h=this.bones.length;h>g;g++){var i=new e.Matrix4;i.getInverse(this.bones[g].skinMatrix),this.boneInverses.push(i)}}for(var g=0,h=this.bones.length;h>g;g++)a.multiplyMatrices(this.bones[g].skinMatrix,this.boneInverses[g]),a.flattenToArrayOffset(this.boneMatrices,16*g);this.useVertexTexture&&(this.boneTexture.needsUpdate=!0)}}(),e.SkinnedMesh.prototype.pose=function(){this.updateMatrixWorld(!0),this.normalizeSkinWeights()},e.SkinnedMesh.prototype.normalizeSkinWeights=function(){if(this.geometry instanceof e.Geometry)for(var a=0;ae;e++){var g=a.morphTargets[e],h=g.name.match(d);if(h&&h.length>1){var i=h[1];h[2];c[i]||(c[i]={start:1/0,end:-(1/0)});var j=c[i];ej.end&&(j.end=e),b||(b=i)}}a.firstAnimation=b},e.MorphAnimMesh.prototype.setAnimationLabel=function(a,b,c){this.geometry.animations||(this.geometry.animations={}),this.geometry.animations[a]={start:b,end:c}},e.MorphAnimMesh.prototype.playAnimation=function(a,b){var c=this.geometry.animations[a];c?(this.setFrameRange(c.start,c.end),this.duration=1e3*((c.end-c.start)/b),this.time=0):e.onwarning("animation["+a+"] undefined")},e.MorphAnimMesh.prototype.updateAnimation=function(a){var b=this.duration/this.length;this.time+=this.direction*a,this.mirroredLoop?(this.time>this.duration||this.time<0)&&(this.direction*=-1,this.time>this.duration&&(this.time=this.duration,this.directionBackwards=!0),this.time<0&&(this.time=0,this.directionBackwards=!1)):(this.time=this.time%this.duration,this.time<0&&(this.time+=this.duration));var c=this.startKeyframe+e.Math.clamp(Math.floor(this.time/b),0,this.length-1);c!==this.currentKeyframe&&(this.morphTargetInfluences[this.lastKeyframe]=0,this.morphTargetInfluences[this.currentKeyframe]=1,this.morphTargetInfluences[c]=0,this.lastKeyframe=this.currentKeyframe,this.currentKeyframe=c);var d=this.time%b/b;this.directionBackwards&&(d=1-d),this.morphTargetInfluences[this.currentKeyframe]=d,this.morphTargetInfluences[this.lastKeyframe]=1-d},e.MorphAnimMesh.prototype.clone=function(a){return void 0===a&&(a=new e.MorphAnimMesh(this.geometry,this.material)),a.duration=this.duration,a.mirroredLoop=this.mirroredLoop,a.time=this.time,a.lastKeyframe=this.lastKeyframe,a.currentKeyframe=this.currentKeyframe,a.direction=this.direction,a.directionBackwards=this.directionBackwards,e.Mesh.prototype.clone.call(this,a),a},e.LOD=function(){e.Object3D.call(this),this.objects=[]},e.LOD.prototype=Object.create(e.Object3D.prototype),e.LOD.prototype.addLevel=function(a,b){void 0===b&&(b=0),b=Math.abs(b);for(var c=0;cb&&!(a1){a.setFromMatrixPosition(c.matrixWorld),b.setFromMatrixPosition(this.matrixWorld);var d=a.distanceTo(b);this.objects[0].object.visible=!0;for(var e=1,f=this.objects.length;f>e&&d>=this.objects[e].distance;e++)this.objects[e-1].object.visible=!1,this.objects[e].object.visible=!0;for(;f>e;e++)this.objects[e].object.visible=!1}}}(),e.LOD.prototype.clone=function(a){void 0===a&&(a=new e.LOD),e.Object3D.prototype.clone.call(this,a);for(var b=0,c=this.objects.length;c>b;b++){var d=this.objects[b].object.clone();d.visible=0===b,a.addLevel(d,this.objects[b].distance)}return a},e.Sprite=function(){var a=new e.Geometry2(3);return a.vertices.set([-.5,-.5,0,.5,-.5,0,.5,.5,0]),function(b){e.Object3D.call(this),this.geometry=a,this.material=void 0!==b?b:new e.SpriteMaterial}}(),e.Sprite.prototype=Object.create(e.Object3D.prototype),e.Sprite.prototype.updateMatrix=function(){this.matrix.compose(this.position,this.quaternion,this.scale),this.matrixWorldNeedsUpdate=!0},e.Sprite.prototype.clone=function(a){return void 0===a&&(a=new e.Sprite(this.material)),e.Object3D.prototype.clone.call(this,a),a},e.Particle=e.Sprite,e.Scene=function(){e.Object3D.call(this),this.fog=null,this.overrideMaterial=null,this.autoUpdate=!0,this.matrixAutoUpdate=!1,this.__lights=[],this.__objectsAdded=[],this.__objectsRemoved=[]},e.Scene.prototype=Object.create(e.Object3D.prototype),e.Scene.prototype.__addObject=function(a){if(a instanceof e.Light)-1===this.__lights.indexOf(a)&&this.__lights.push(a),a.target&&void 0===a.target.parent&&this.add(a.target);else if(!(a instanceof e.Camera||a instanceof e.Bone)){this.__objectsAdded.push(a);var b=this.__objectsRemoved.indexOf(a);-1!==b&&this.__objectsRemoved.splice(b,1)}this.dispatchEvent({type:"objectAdded",object:a}),a.dispatchEvent({type:"addedToScene",scene:this});for(var c=0;ca;a++){var c=C[a],d=c.color;c instanceof e.AmbientLight?Ga.add(d):c instanceof e.DirectionalLight?Ha.add(d):c instanceof e.PointLight&&Ia.add(d)}}function c(a,b,c){for(var d=0,f=C.length;f>d;d++){var g=C[d];if(Ba.copy(g.color),g instanceof e.DirectionalLight){var h=Ja.setFromMatrixPosition(g.matrixWorld).normalize(),i=b.dot(h);if(0>=i)continue;i*=g.intensity,c.add(Ba.multiplyScalar(i))}else if(g instanceof e.PointLight){var h=Ja.setFromMatrixPosition(g.matrixWorld),i=b.dot(Ja.subVectors(h,a).normalize());if(0>=i)continue;if(i*=0==g.distance?1:1-Math.min(a.distanceTo(h)/g.distance,1),0==i)continue;i*=g.intensity,c.add(Ba.multiplyScalar(i))}}}function f(a,b,c){r(c.opacity),s(c.blending);var d=b.scale.x*ga,f=b.scale.y*ha,g=.5*Math.sqrt(d*d+f*f);if(Fa.min.set(a.x-g,a.y-g),Fa.max.set(a.x+g,a.y+g),c instanceof e.SpriteMaterial||c instanceof e.ParticleSystemMaterial){var h=c.map;if(null!==h){h.hasEventListener("update",l)===!1&&(void 0!==h.image&&h.image.width>0&&m(h),h.addEventListener("update",l));var i=Ca[h.id];x(void 0!==i?i:"rgba( 0, 0, 0, 1 )");var j=h.image,k=j.width*h.offset.x,n=j.height*h.offset.y,o=j.width*h.repeat.x,p=j.height*h.repeat.y,q=d/o,t=f/p;ia.save(),ia.translate(a.x,a.y),0!==c.rotation&&ia.rotate(c.rotation),ia.translate(-d/2,-f/2),ia.scale(q,t),ia.translate(-k,-n),ia.fillRect(k,n,o,p),ia.restore()}else x(c.color.getStyle()),ia.save(),ia.translate(a.x,a.y),0!==c.rotation&&ia.rotate(c.rotation),ia.scale(d,-f),ia.fillRect(-.5,-.5,1,1),ia.restore()}else c instanceof e.SpriteCanvasMaterial&&(w(c.color.getStyle()),x(c.color.getStyle()),ia.save(),ia.translate(a.x,a.y),0!==c.rotation&&ia.rotate(c.rotation),ia.scale(d,f),c.program(ia),ia.restore())}function g(a,b,c,d){if(r(d.opacity),s(d.blending),ia.beginPath(),ia.moveTo(a.positionScreen.x,a.positionScreen.y),ia.lineTo(b.positionScreen.x,b.positionScreen.y),d instanceof e.LineBasicMaterial){if(t(d.linewidth),u(d.linecap),v(d.linejoin),d.vertexColors!==e.VertexColors)w(d.color.getStyle());else{var f=c.vertexColors[0].getStyle(),g=c.vertexColors[1].getStyle();if(f===g)w(f);else{try{var h=ia.createLinearGradient(a.positionScreen.x,a.positionScreen.y,b.positionScreen.x,b.positionScreen.y);h.addColorStop(0,f),h.addColorStop(1,g)}catch(i){h=f}w(h)}}ia.stroke(),Fa.expandByScalar(2*d.linewidth)}else d instanceof e.LineDashedMaterial&&(t(d.linewidth),u(d.linecap),v(d.linejoin),w(d.color.getStyle()),y(d.dashSize,d.gapSize),ia.stroke(),Fa.expandByScalar(2*d.linewidth),y(null,null))}function h(a,b,d,f,g,h,l,m){ba.info.render.vertices+=3,ba.info.render.faces++,r(m.opacity),s(m.blending),H=a.positionScreen.x,I=a.positionScreen.y,J=b.positionScreen.x,K=b.positionScreen.y,L=d.positionScreen.x,M=d.positionScreen.y,i(H,I,J,K,L,M),(m instanceof e.MeshLambertMaterial||m instanceof e.MeshPhongMaterial||m instanceof e.MeshPhysicalMaterial)&&null===m.map?(za.copy(m.color),Aa.copy(m.emissive),m.vertexColors===e.FaceColors&&za.multiply(l.color),m.wireframe===!1&&m.shading===e.SmoothShading&&3===l.vertexNormalsLength?(va.copy(Ga),wa.copy(Ga),xa.copy(Ga),c(l.v1.positionWorld,l.vertexNormalsModel[0],va),c(l.v2.positionWorld,l.vertexNormalsModel[1],wa),c(l.v3.positionWorld,l.vertexNormalsModel[2],xa),va.multiply(za).add(Aa),wa.multiply(za).add(Aa),xa.multiply(za).add(Aa),ya.addColors(wa,xa).multiplyScalar(.5),P=p(va,wa,xa,ya),o(H,I,J,K,L,M,0,0,1,0,0,1,P)):(ua.copy(Ga),c(l.centroidModel,l.normalModel,ua),ua.multiply(za).add(Aa),m.wireframe===!0?j(ua,m.wireframeLinewidth,m.wireframeLinecap,m.wireframeLinejoin):k(ua))):m instanceof e.MeshBasicMaterial||m instanceof e.MeshLambertMaterial||m instanceof e.MeshPhongMaterial?null!==m.map?m.map.mapping instanceof e.UVMapping&&(Q=l.uvs[0],n(H,I,J,K,L,M,Q[f].x,Q[f].y,Q[g].x,Q[g].y,Q[h].x,Q[h].y,m.map)):null!==m.envMap?m.envMap.mapping instanceof e.SphericalReflectionMapping&&(Ka.copy(l.vertexNormalsModel[f]).applyMatrix3(La),R=.5*Ka.x+.5,S=.5*Ka.y+.5,Ka.copy(l.vertexNormalsModel[g]).applyMatrix3(La),T=.5*Ka.x+.5,U=.5*Ka.y+.5,Ka.copy(l.vertexNormalsModel[h]).applyMatrix3(La),V=.5*Ka.x+.5,W=.5*Ka.y+.5,n(H,I,J,K,L,M,R,S,T,U,V,W,m.envMap)):(ua.copy(m.color),m.vertexColors===e.FaceColors&&ua.multiply(l.color),m.wireframe===!0?j(ua,m.wireframeLinewidth,m.wireframeLinecap,m.wireframeLinejoin):k(ua)):m instanceof e.MeshDepthMaterial?(N=D.near,O=D.far,va.r=va.g=va.b=1-z(a.positionScreen.z*a.positionScreen.w,N,O),wa.r=wa.g=wa.b=1-z(b.positionScreen.z*b.positionScreen.w,N,O),xa.r=xa.g=xa.b=1-z(d.positionScreen.z*d.positionScreen.w,N,O),ya.addColors(wa,xa).multiplyScalar(.5),P=p(va,wa,xa,ya),o(H,I,J,K,L,M,0,0,1,0,0,1,P)):m instanceof e.MeshNormalMaterial&&(m.shading===e.FlatShading?(Ka.copy(l.normalModel).applyMatrix3(La),ua.setRGB(Ka.x,Ka.y,Ka.z).multiplyScalar(.5).addScalar(.5),m.wireframe===!0?j(ua,m.wireframeLinewidth,m.wireframeLinecap,m.wireframeLinejoin):k(ua)):m.shading===e.SmoothShading&&(Ka.copy(l.vertexNormalsModel[f]).applyMatrix3(La),va.setRGB(Ka.x,Ka.y,Ka.z).multiplyScalar(.5).addScalar(.5),Ka.copy(l.vertexNormalsModel[g]).applyMatrix3(La),wa.setRGB(Ka.x,Ka.y,Ka.z).multiplyScalar(.5).addScalar(.5),Ka.copy(l.vertexNormalsModel[h]).applyMatrix3(La),xa.setRGB(Ka.x,Ka.y,Ka.z).multiplyScalar(.5).addScalar(.5),ya.addColors(wa,xa).multiplyScalar(.5),P=p(va,wa,xa,ya),o(H,I,J,K,L,M,0,0,1,0,0,1,P)))}function i(a,b,c,d,e,f){ia.beginPath(),ia.moveTo(a,b),ia.lineTo(c,d),ia.lineTo(e,f),ia.closePath()}function j(a,b,c,d){t(b),u(c),v(d),w(a.getStyle()),ia.stroke(),Fa.expandByScalar(2*b)}function k(a){x(a.getStyle()),ia.fill()}function l(a){m(a.target)}function m(a){var b=a.wrapS===e.RepeatWrapping,c=a.wrapT===e.RepeatWrapping,d=a.image,f=document.createElement("canvas");f.width=d.width,f.height=d.height;var g=f.getContext("2d");g.setTransform(1,0,0,-1,0,d.height),g.drawImage(d,0,0),Ca[a.id]=ia.createPattern(f,b===!0&&c===!0?"repeat":b===!0&&c===!1?"repeat-x":b===!1&&c===!0?"repeat-y":"no-repeat")}function n(a,b,c,d,f,g,h,i,j,k,n,o,p){if(!(p instanceof e.DataTexture)){p.hasEventListener("update",l)===!1&&(void 0!==p.image&&p.image.width>0&&m(p),p.addEventListener("update",l));var q=Ca[p.id];if(void 0===q)return x("rgba(0,0,0,1)"),void ia.fill();x(q);var r,s,t,u,v,w,y,z,A=p.offset.x/p.repeat.x,B=p.offset.y/p.repeat.y,C=p.image.width*p.repeat.x,D=p.image.height*p.repeat.y;h=(h+A)*C,i=(i+B)*D,j=(j+A)*C,k=(k+B)*D,n=(n+A)*C,o=(o+B)*D,c-=a,d-=b,f-=a,g-=b,j-=h,k-=i,n-=h,o-=i,y=j*o-n*k,0!==y&&(z=1/y,r=(o*c-k*f)*z,s=(o*d-k*g)*z,t=(j*f-n*c)*z,u=(j*g-n*d)*z,v=a-r*h-t*i,w=b-s*h-u*i,ia.save(),ia.transform(r,s,t,u,v,w),ia.fill(),ia.restore())}}function o(a,b,c,d,e,f,g,h,i,j,k,l,m){var n,o,p,q,r,s,t,u,v=m.width-1,w=m.height-1;g*=v,h*=w,i*=v,j*=w,k*=v,l*=w,c-=a,d-=b,e-=a,f-=b,i-=g,j-=h,k-=g,l-=h,t=i*l-k*j,u=1/t,n=(l*c-j*e)*u,o=(l*d-j*f)*u,p=(i*e-k*c)*u,q=(i*f-k*d)*u,r=a-n*g-p*h,s=b-o*g-q*h,ia.save(),ia.transform(n,o,p,q,r,s),ia.clip(),ia.drawImage(m,0,0),ia.restore()}function p(a,b,c,d){return $[0]=255*a.r|0,$[1]=255*a.g|0,$[2]=255*a.b|0,$[4]=255*b.r|0,$[5]=255*b.g|0,$[6]=255*b.b|0,$[8]=255*c.r|0,$[9]=255*c.g|0,$[10]=255*c.b|0,$[12]=255*d.r|0,$[13]=255*d.g|0,$[14]=255*d.b|0,Y.putImageData(Z,0,0),aa.drawImage(X,0,0),_}function q(a,b,c){var d,e=b.x-a.x,f=b.y-a.y,g=e*e+f*f;0!==g&&(d=c/Math.sqrt(g),e*=d,f*=d,b.x+=e,b.y+=f,a.x-=e,a.y-=f)}function r(a){la!==a&&(ia.globalAlpha=a,la=a)}function s(a){ma!==a&&(a===e.NormalBlending?ia.globalCompositeOperation="source-over":a===e.AdditiveBlending?ia.globalCompositeOperation="lighter":a===e.SubtractiveBlending&&(ia.globalCompositeOperation="darker"),ma=a)}function t(a){pa!==a&&(ia.lineWidth=a,pa=a)}function u(a){qa!==a&&(ia.lineCap=a,qa=a)}function v(a){ra!==a&&(ia.lineJoin=a,ra=a)}function w(a){na!==a&&(ia.strokeStyle=a,na=a)}function x(a){oa!==a&&(ia.fillStyle=a,oa=a)}function y(a,b){sa===a&&ta===b||(ia.setLineDash([a,b]),sa=a,ta=b)}console.log("THREE.CanvasRenderer",e.REVISION);var z=e.Math.smoothstep;a=a||{};var A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,$,_,aa,ba=this,ca=new e.Projector,da=void 0!==a.canvas?a.canvas:document.createElement("canvas"),ea=da.width,fa=da.height,ga=Math.floor(ea/2),ha=Math.floor(fa/2),ia=da.getContext("2d",{alpha:a.alpha===!0}),ja=new e.Color(0),ka=0,la=1,ma=0,na=null,oa=null,pa=null,qa=null,ra=null,sa=null,ta=0,ua=(new e.RenderableVertex,new e.RenderableVertex,new e.Color),va=new e.Color,wa=new e.Color,xa=new e.Color,ya=new e.Color,za=new e.Color,Aa=new e.Color,Ba=new e.Color,Ca={},Da=new e.Box2,Ea=new e.Box2,Fa=new e.Box2,Ga=new e.Color,Ha=new e.Color,Ia=new e.Color,Ja=new e.Vector3,Ka=new e.Vector3,La=new e.Matrix3,Ma=16;X=document.createElement("canvas"),X.width=X.height=2,Y=X.getContext("2d"),Y.fillStyle="rgba(0,0,0,1)",Y.fillRect(0,0,2,2),Z=Y.getImageData(0,0,2,2),$=Z.data,_=document.createElement("canvas"),_.width=_.height=Ma,aa=_.getContext("2d"),aa.translate(-Ma/2,-Ma/2),aa.scale(Ma,Ma),Ma--,void 0===ia.setLineDash&&(void 0!==ia.mozDash?ia.setLineDash=function(a){ia.mozDash=null!==a[0]?a:null}:ia.setLineDash=function(){}),this.domElement=da,this.devicePixelRatio=void 0!==a.devicePixelRatio?a.devicePixelRatio:void 0!==d.devicePixelRatio?d.devicePixelRatio:1,this.autoClear=!0,this.sortObjects=!0,this.sortElements=!0,this.info={render:{vertices:0,faces:0}},this.supportsVertexTextures=function(){},this.setFaceCulling=function(){},this.setSize=function(a,b,c){ea=a*this.devicePixelRatio,fa=b*this.devicePixelRatio,ga=Math.floor(ea/2),ha=Math.floor(fa/2),da.width=ea,da.height=fa,1!==this.devicePixelRatio&&c!==!1&&(da.style.width=a+"px",da.style.height=b+"px"),Da.min.set(-ga,-ha),Da.max.set(ga,ha),Ea.min.set(-ga,-ha),Ea.max.set(ga,ha),la=1,ma=0,na=null,oa=null,pa=null,qa=null,ra=null},this.setClearColor=function(a,b){ja.set(a),ka=void 0!==b?b:1,Ea.min.set(-ga,-ha),Ea.max.set(ga,ha)},this.setClearColorHex=function(a,b){e.onwarning("DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead."),this.setClearColor(a,b)},this.getMaxAnisotropy=function(){return 0},this.clear=function(){ia.setTransform(1,0,0,-1,ga,ha),Ea.empty()===!1&&(Ea.intersect(Da),Ea.expandByScalar(2),1>ka&&ia.clearRect(0|Ea.min.x,0|Ea.min.y,Ea.max.x-Ea.min.x|0,Ea.max.y-Ea.min.y|0),ka>0&&(s(e.NormalBlending),r(1),x("rgba("+Math.floor(255*ja.r)+","+Math.floor(255*ja.g)+","+Math.floor(255*ja.b)+","+ka+")"),ia.fillRect(0|Ea.min.x,0|Ea.min.y,Ea.max.x-Ea.min.x|0,Ea.max.y-Ea.min.y|0)),Ea.makeEmpty())},this.clearColor=function(){},this.clearDepth=function(){},this.clearStencil=function(){},this.render=function(a,c){if(c instanceof e.Camera==!1)return void e.onerror("THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.");this.autoClear===!0&&this.clear(),ia.setTransform(1,0,0,-1,ga,ha),ba.info.render.vertices=0,ba.info.render.faces=0,A=ca.projectScene(a,c,this.sortObjects,this.sortElements),B=A.elements,C=A.lights,D=c,La.getNormalMatrix(c.matrixWorldInverse),b();for(var d=0,i=B.length;i>d;d++){var j=B[d],k=j.material;if(void 0!==k&&k.visible!==!1){if(Fa.makeEmpty(),j instanceof e.RenderableSprite)E=j,E.x*=ga,E.y*=ha,f(E,j,k);else if(j instanceof e.RenderableLine)E=j.v1,F=j.v2,E.positionScreen.x*=ga,E.positionScreen.y*=ha,F.positionScreen.x*=ga,F.positionScreen.y*=ha,Fa.setFromPoints([E.positionScreen,F.positionScreen]),Da.isIntersectionBox(Fa)===!0&&g(E,F,j,k);else if(j instanceof e.RenderableFace){if(E=j.v1,F=j.v2,G=j.v3,E.positionScreen.z<-1||E.positionScreen.z>1)continue;if(F.positionScreen.z<-1||F.positionScreen.z>1)continue;if(G.positionScreen.z<-1||G.positionScreen.z>1)continue;E.positionScreen.x*=ga,E.positionScreen.y*=ha,F.positionScreen.x*=ga,F.positionScreen.y*=ha,G.positionScreen.x*=ga,G.positionScreen.y*=ha,k.overdraw>0&&(q(E.positionScreen,F.positionScreen,k.overdraw),q(F.positionScreen,G.positionScreen,k.overdraw),q(G.positionScreen,E.positionScreen,k.overdraw)),Fa.setFromPoints([E.positionScreen,F.positionScreen,G.positionScreen]),Da.isIntersectionBox(Fa)===!0&&h(E,F,G,0,1,2,j,k)}Ea.union(Fa)}}ia.setTransform(1,0,0,1,0,0)}},e.ShaderChunk={common:["#define PI 3.14159","#define PI2 6.28318","#define LOG2 1.442695","#define ENCODING_Linear 3000","#define ENCODING_sRGB 3001","#define ENCODING_RGBE 3002","#define ENCODING_RGBM7 3004","#define ENCODING_RGBM16 3005","#define SPECULAR_COEFF 0.18","float square( float a ) { return a*a; }","vec2 square( vec2 a ) { return vec2( a.x*a.x, a.y*a.y ); }","vec3 square( vec3 a ) { return vec3( a.x*a.x, a.y*a.y, a.z*a.z ); }","vec4 square( vec4 a ) { return vec4( a.x*a.x, a.y*a.y, a.z*a.z, a.w*a.w ); }","float saturate( float a ) { return clamp( a, 0.0, 1.0 ); }","vec2 saturate( vec2 a ) { return clamp( a, 0.0, 1.0 ); }","vec3 saturate( vec3 a ) { return clamp( a, 0.0, 1.0 ); }","vec4 saturate( vec4 a ) { return clamp( a, 0.0, 1.0 ); }","float average( float a ) { return a; }","float average( vec2 a ) { return ( a.x + a.y) * 0.5; }","float average( vec3 a ) { return ( a.x + a.y + a.z) * 0.3333333333; }","float average( vec4 a ) { return ( a.x + a.y + a.z + a.w) * 0.25; }","float whiteCompliment( float a ) { return saturate( 1.0 - a ); }","vec2 whiteCompliment( vec2 a ) { return saturate( vec2(1.0) - a ); }","vec3 whiteCompliment( vec3 a ) { return saturate( vec3(1.0) - a ); }","vec4 whiteCompliment( vec4 a ) { return saturate( vec4(1.0) - a ); }","vec3 projectOnPlane( vec3 point, vec3 pointOnPlane, vec3 planeNormal) {","float distance = dot( planeNormal, point-pointOnPlane );","return point - distance * planeNormal;","}","float sideOfPlane( vec3 point, vec3 pointOnPlane, vec3 planeNormal ) {","return sign( dot( point - pointOnPlane, planeNormal ) );","}","vec2 applyUVOffsetRepeat( vec2 uv, vec4 offsetRepeat ) {","return uv * offsetRepeat.zw + offsetRepeat.xy;","}","vec3 linePlaneIntersect( vec3 pointOnLine, vec3 lineDirection, vec3 pointOnPlane, vec3 planeNormal ) {","return pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) );","}","vec4 applyGainBrightness( vec4 texel, vec4 gainBrightnessCoeff ) {","if( gainBrightnessCoeff.w < 0.0 ) {","texel.xyz = whiteCompliment( texel.xyz );","}","texel.xyz = ( texel.xyz - vec3( gainBrightnessCoeff.x ) ) * gainBrightnessCoeff.y + vec3( gainBrightnessCoeff.z + gainBrightnessCoeff.x );","return texel;","}","vec4 texelDecode( vec4 texel, int encoding ) {","if( encoding == 3001 ) {","texel = vec4( pow( max( texel.xyz, vec3( 0.0 ) ), vec3( 2.2 ) ), texel.w );","}","else if( encoding == 3002 ) {","texel = vec4( texel.xyz * pow( 2.0, texel.w*256.0 - 128.0 ), 1.0 );","}","else if( encoding == 3004 ) {","texel = vec4( texel.xyz * texel.w * 7.0, 1.0 );","}","else if( encoding == 3005 ) {","texel = vec4( texel.xyz * texel.w * 16.0, 1.0 );","}","return texel;","}"].join("\n"),fog_pars_fragment:["#ifdef USE_FOG","uniform vec3 fogColor;","#ifdef FOG_EXP2","uniform float fogDensity;","#else","uniform float fogNear;","uniform float fogFar;","#endif","#endif"].join("\n"),fog_fragment:["#ifdef USE_FOG","float depth = gl_FragCoord.z / gl_FragCoord.w;","#ifdef FOG_EXP2","float fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );","fogFactor = 1.0 - saturate( fogFactor );","#else","float fogFactor = smoothstep( fogNear, fogFar, depth );","#endif","gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );","#endif"].join("\n"),diffuseenvmap_pars_fragment:["#if defined( USE_DIFFUSEENVMAP )","uniform samplerCube diffuseEnvMap;","uniform int diffuseEnvEncoding;","#endif"].join("\n"),envmap_pars_fragment:["#if defined( USE_DIFFUSEENVMAP ) || defined( USE_ENVMAP )","uniform float flipEnvMap;","#endif","#ifdef USE_ENVMAP","uniform float reflectivity;","uniform samplerCube envMap;","uniform int combine;","uniform int envEncoding;","#endif"].join("\n"),envmap_fragment:["#if defined( USE_ENVMAP ) && ! defined( PHYSICAL )","vec3 worldNormal = vec3( normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz ) );","vec3 worldView = -vec3( normalize( ( vec4( viewDirection, 0.0 ) * viewMatrix ).xyz ) );","vec3 reflectVec = reflect( worldView, worldNormal );","#ifdef DOUBLE_SIDED","float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );","vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );","#else","vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );","#endif","cubeColor = texelDecode( cubeColor, envEncoding );","float fresnelReflectivity = saturate( reflectivity );","if ( combine == 1 ) {","gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, fresnelReflectivity );","} else if ( combine == 2 ) {","gl_FragColor.xyz += cubeColor.xyz * fresnelReflectivity;","} else {","gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, fresnelReflectivity );","}","#endif"].join("\n"),worldpos_vertex:["#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )","#ifdef USE_SKINNING","vec4 worldPosition = modelMatrix * skinned;","#endif","#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )","vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );","#endif","#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )","vec4 worldPosition = modelMatrix * vec4( position, 1.0 );","#endif","#endif"].join("\n"),map_particle_pars_fragment:["#ifdef USE_MAP","uniform sampler2D map;","#endif"].join("\n"),map_particle_fragment:["#ifdef USE_MAP","gl_FragColor = gl_FragColor * texelDecode( texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) ), ENCODING_sRGB );","#endif"].join("\n"),map_pars_vertex:["#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )","varying vec2 vUv;","#endif"].join("\n"),map_pars_fragment:["#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )","varying vec2 vUv;","uniform vec4 offsetRepeat;","uniform vec4 gainBrightness;","#endif","#ifdef USE_MAP","uniform sampler2D map;","#endif"].join("\n"),map_vertex:["#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )","vUv = uv;","#endif"].join("\n"),map_fragment:["#if defined( USE_MAP ) || defined( USE_FALLOFFMAP )","vec2 vUvLocal = applyUVOffsetRepeat( vUv, offsetRepeat );","#endif","#ifdef USE_MAP","vec4 texelColor = clamp( applyGainBrightness( texelDecode( texture2D( map, vUvLocal ), ENCODING_sRGB ), gainBrightness ), vec4(0.0), vec4(1.0) );","gl_FragColor = gl_FragColor * texelColor;","#if defined( PHYSICAL ) || defined( PHONG )","diffuseColor *= texelColor.xyz;","#endif","#endif"].join("\n"),falloffmap_pars_fragment:["#ifdef USE_FALLOFFMAP","uniform sampler2D falloffMap;","#endif"].join("\n"),opacitymap_pars_fragment:["#ifdef USE_OPACITYMAP","uniform sampler2D opacityMap;","uniform vec4 opacityOffsetRepeat;","uniform vec4 opacityGainBrightness;","#endif"].join("\n"),opacitymap_fragment:["#ifdef USE_OPACITYMAP","vec2 vOpacityUv = applyUVOffsetRepeat( vUv, opacityOffsetRepeat );","vec4 texelOpacity = applyGainBrightness( texture2D( opacityMap, vOpacityUv ), opacityGainBrightness );","gl_FragColor.w = clamp( gl_FragColor.w * texelOpacity.r, 0.0, 1.0 );","#endif"].join("\n"),translucencymap_pars_fragment:["#ifdef USE_TRANSLUCENCYMAP","uniform sampler2D translucencyMap;","uniform vec4 translucencyOffsetRepeat;","uniform vec4 translucencyGainBrightness;","#endif"].join("\n"),translucencymap_fragment:["#ifdef USE_TRANSLUCENCYMAP","vec2 vTranslucencyUv = applyUVOffsetRepeat( vUv, translucencyOffsetRepeat );","vec4 texelTranslucency = applyGainBrightness( texture2D( translucencyMap, vTranslucencyUv ), translucencyGainBrightness );","translucencyColor.xyz = clamp( translucencyColor.xyz * texelTranslucency.xyz, vec3( 0.0 ), vec3( 1.0 ) );","#endif"].join("\n"),lightmap_pars_fragment:["#if defined( USE_LIGHTMAP ) || defined( USE_EMISSIVEMAP )","varying vec2 vUv2;","#endif","#if defined( USE_LIGHTMAP )","uniform sampler2D lightMap;","#endif","#if defined( USE_EMISSIVEMAP )","uniform sampler2D emissiveMap;","#endif"].join("\n"), +lightmap_pars_vertex:["#if defined( USE_LIGHTMAP ) || defined( USE_EMISSIVEMAP )","varying vec2 vUv2;","#endif"].join("\n"),lightmap_fragment:["#ifdef USE_LIGHTMAP","#endif"].join("\n"),lightmap_vertex:["#if defined( USE_LIGHTMAP ) || defined( USE_EMISSIVEMAP )","vUv2 = uv2;","#endif"].join("\n"),bumpmap_pars_fragment:["#ifdef USE_BUMPMAP","uniform sampler2D bumpMap;","uniform vec4 bumpOffsetRepeat;","uniform float bumpScale;","vec2 dHdxy_fwd() {","#ifdef GL_OES_standard_derivatives","vec2 vBumpUv = applyUVOffsetRepeat( vUv, bumpOffsetRepeat );","vec2 dSTdx = dFdx( vBumpUv );","vec2 dSTdy = dFdy( vBumpUv );","float Hll = bumpScale * texture2D( bumpMap, vBumpUv ).x;","float dBx = bumpScale * texture2D( bumpMap, vBumpUv + dSTdx ).x - Hll;","float dBy = bumpScale * texture2D( bumpMap, vBumpUv + dSTdy ).x - Hll;","return vec2( dBx, dBy );","#else","return vec2( 0.0, 0.0 );","#endif","}","vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {","#ifdef GL_OES_standard_derivatives","vec3 vSigmaX = dFdx( surf_pos );","vec3 vSigmaY = dFdy( surf_pos );","vec3 vN = surf_norm;","vec3 R1 = cross( vSigmaY, vN );","vec3 R2 = cross( vN, vSigmaX );","float fDet = dot( vSigmaX, R1 );","vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );","return normalize( abs( fDet ) * surf_norm - vGrad );","#else","return surf_norm;","#endif","}","#endif"].join("\n"),lightattenuation_func_fragment:["float calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {","if ( decayExponent > 0.0 && cutoffDistance > 0.0 ) {","return pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );","}","else if ( decayExponent < 0.0 ) {","float numerator = 1.0;","if( cutoffDistance > 0.0 ) {","numerator = ( saturate( 1.0 - pow( lightDistance / cutoffDistance, 4.0 ) ) );","numerator *= numerator;","} ","return numerator / ( ( lightDistance * lightDistance ) + 1.0 );","}","else {","return 1.0;","}","}"].join("\n"),normalmap_pars_fragment:["#ifdef USE_NORMALMAP","uniform sampler2D normalMap;","uniform vec4 normalOffsetRepeat;","uniform vec2 normalScale;","vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {","#ifdef GL_OES_standard_derivatives","vec2 vNormalUv = applyUVOffsetRepeat( vUv, normalOffsetRepeat );","vec3 q0 = dFdx( eye_pos.xyz );","vec3 q1 = dFdy( eye_pos.xyz );","vec2 st0 = dFdx( vNormalUv.st );","vec2 st1 = dFdy( vNormalUv.st );","vec3 S = normalize( q0 * st1.t - q1 * st0.t );","vec3 T = normalize( -q0 * st1.s + q1 * st0.s );","vec3 N = normalize( surf_norm );","vec3 mapN = texture2D( normalMap, vNormalUv ).xyz * 2.0 - 1.0;","mapN.xy = normalScale * mapN.xy;","mat3 tsn = mat3( S, T, N );","return normalize( tsn * mapN );","#else","return surf_norm;","#endif","}","#endif"].join("\n"),anisotropymap_pars_fragment:["#ifdef USE_ANISOTROPYMAP","uniform sampler2D anisotropyMap;","uniform vec4 anisotropyGainBrightness;","uniform vec4 anisotropyOffsetRepeat;","#endif"].join("\n"),anisotropymap_fragment:["#ifdef USE_ANISOTROPYMAP","vec2 vAnisotropyUv = applyUVOffsetRepeat( vUv, anisotropyOffsetRepeat );","#else","#ifdef ANISOTROPY","#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )","vec2 vAnisotropyUv = vUv;","#else","vec2 vAnisotropyUv = vec2( 0, 0 );","#endif","#endif","#endif","float anisotropyStrength = anisotropy;","#ifdef USE_ANISOTROPYMAP","vec4 texelAnisotropy = applyGainBrightness( texture2D( anisotropyMap, vAnisotropyUv ), anisotropyGainBrightness );","anisotropyStrength = clamp( anisotropyStrength + texelAnisotropy.r, -1.0, 1.0 );","#endif"].join("\n"),anisotropyrotationmap_pars_fragment:["#ifdef USE_ANISOTROPYROTATIONMAP","uniform sampler2D anisotropyRotationMap;","uniform vec4 anisotropyRotationGainBrightness;","uniform vec4 anisotropyRotationOffsetRepeat;","#endif"].join("\n"),anisotropyrotationmap_fragment:["float anisotropyRotationStrength = anisotropyRotation;","#ifdef USE_ANISOTROPYROTATIONMAP","vec2 vAnisotropyRotationUv = applyUVOffsetRepeat( vUv, anisotropyRotationOffsetRepeat );","vec4 texelAnisotropyRotation = applyGainBrightness( texture2D( anisotropyRotationMap, vAnisotropyRotationUv ), anisotropyRotationGainBrightness );","anisotropyRotationStrength += texelAnisotropyRotation.r;","#endif"].join("\n"),metallicmap_pars_fragment:["#ifdef USE_METALLICMAP","uniform sampler2D metallicMap;","uniform vec4 metallicGainBrightness;","uniform vec4 metallicOffsetRepeat;","#endif"].join("\n"),metallicmap_fragment:["float metallicStrength = metallic;","#ifdef USE_METALLICMAP","vec2 vMetallicUv = applyUVOffsetRepeat( vUv, metallicOffsetRepeat );","vec4 texelMetallic = applyGainBrightness( texture2D( metallicMap, vMetallicUv ), metallicGainBrightness );","metallicStrength = clamp( metallicStrength * texelMetallic.r, 0.0, 1.0 );","#endif"].join("\n"),roughnessmap_pars_fragment:["#ifdef USE_ROUGHNESSMAP","uniform sampler2D roughnessMap;","uniform vec4 roughnessOffsetRepeat;","uniform vec4 roughnessGainBrightness;","#endif"].join("\n"),roughnessmap_fragment:["float roughnessStrength = roughness;","#ifdef USE_ROUGHNESSMAP","vec2 vRoughnessUv = applyUVOffsetRepeat( vUv, roughnessOffsetRepeat );","vec4 texelRoughness = applyGainBrightness( texture2D( roughnessMap, vRoughnessUv ), roughnessGainBrightness );","roughnessStrength = clamp( roughnessStrength * texelRoughness.r, 0.0, 1.0 );","#endif"].join("\n"),specularmap_pars_fragment:["#ifdef USE_SPECULARMAP","uniform sampler2D specularMap;","uniform vec4 specularGainBrightness;","uniform vec4 specularOffsetRepeat;","#endif"].join("\n"),specularmap_fragment:["#ifdef PHYSICAL","vec3 specularColor = specular;","#else","float specularStrength = 1.0;","#endif","#ifdef USE_SPECULARMAP","vec2 vSpecularUv = applyUVOffsetRepeat( vUv, specularOffsetRepeat );","vec4 texelSpecular = applyGainBrightness( texelDecode( texture2D( specularMap, vSpecularUv ), ENCODING_sRGB ), specularGainBrightness );","#ifdef PHYSICAL","specularColor.rgb = clamp( specularColor.rgb * texelSpecular.rgb, vec3( 0.0 ), vec3( 1.0 ) );","#else","specularStrength = clamp( specularStrength * texelSpecular.r, 0.0, 1.0 );","#endif","#endif"].join("\n"),lights_lambert_pars_vertex:["uniform vec3 ambient;","uniform vec3 diffuse;","uniform vec3 emissive;","uniform vec3 ambientLightColor;","#if MAX_DIR_LIGHTS > 0","uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];","uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];","#endif","#if MAX_HEMI_LIGHTS > 0","uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];","#endif","#if MAX_POINT_LIGHTS > 0","uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];","uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];","uniform float pointLightDistance[ MAX_POINT_LIGHTS ];","uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];","#endif","#if MAX_SPOT_LIGHTS > 0","uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];","uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];","uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];","uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];","uniform float spotLightDecayExponent[ MAX_SPOT_LIGHTS ];","#endif","#if MAX_AREA_LIGHTS > 0","uniform vec3 areaLightColor[ MAX_AREA_LIGHTS ];","uniform vec3 areaLightPosition[ MAX_AREA_LIGHTS ];","uniform vec3 areaLightWidth[ MAX_AREA_LIGHTS ];","uniform vec3 areaLightHeight[ MAX_AREA_LIGHTS ];","uniform float areaLightDistance[ MAX_AREA_LIGHTS ];","uniform float areaLightDecayExponent[ MAX_AREA_LIGHTS ];","#endif","#ifdef WRAP_AROUND","uniform vec3 wrapRGB;","#endif"].join("\n"),lights_lambert_vertex:["vLightFront = vec3( 0.0 );","#ifdef DOUBLE_SIDED","vLightBack = vec3( 0.0 );","#endif","transformedNormal = normalize( transformedNormal );","#if MAX_DIR_LIGHTS > 0","for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {","vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );","vec3 dirVector = normalize( lDirection.xyz );","float dotProduct = dot( transformedNormal, dirVector );","vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );","#ifdef DOUBLE_SIDED","vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );","#ifdef WRAP_AROUND","vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );","#endif","#endif","#ifdef WRAP_AROUND","vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );","directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );","#ifdef DOUBLE_SIDED","directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );","#endif","#endif","vLightFront += directionalLightColor[ i ] * directionalLightWeighting;","#ifdef DOUBLE_SIDED","vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;","#endif","}","#endif","#if MAX_POINT_LIGHTS > 0","for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );","vec3 lVector = lPosition.xyz - mvPosition.xyz;","float distanceAttenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );","lVector = normalize( lVector );","float dotProduct = dot( transformedNormal, lVector );","vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );","#ifdef DOUBLE_SIDED","vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );","#ifdef WRAP_AROUND","vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );","#endif","#endif","#ifdef WRAP_AROUND","vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );","pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );","#ifdef DOUBLE_SIDED","pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );","#endif","#endif","vLightFront += pointLightColor[ i ] * pointLightWeighting * distanceAttenuation;","#ifdef DOUBLE_SIDED","vLightBack += pointLightColor[ i ] * pointLightWeightingBack * distanceAttenuation;","#endif","}","#endif","#if MAX_SPOT_LIGHTS > 0","for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );","vec3 lVector = lPosition.xyz - mvPosition.xyz;","float distanceAttenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );","float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );","if ( spotEffect > spotLightAngleCos[ i ] ) {","spotEffect = pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] );","lVector = normalize( lVector );","float dotProduct = dot( transformedNormal, lVector );","vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );","#ifdef DOUBLE_SIDED","vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );","#ifdef WRAP_AROUND","vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );","#endif","#endif","#ifdef WRAP_AROUND","vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );","spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );","#ifdef DOUBLE_SIDED","spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );","#endif","#endif","vLightFront += spotLightColor[ i ] * spotLightWeighting * distanceAttenuation * spotEffect;","#ifdef DOUBLE_SIDED","vLightBack += spotLightColor[ i ] * spotLightWeightingBack * distanceAttenuation * spotEffect;","#endif","}","}","#endif","#if MAX_HEMI_LIGHTS > 0","for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {","vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );","vec3 lVector = normalize( lDirection.xyz );","float dotProduct = dot( transformedNormal, lVector );","float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;","float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;","vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );","#ifdef DOUBLE_SIDED","vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );","#endif","}","#endif","vLightFront = ( vLightFront + ambientLightColor + ambient) * diffuse + emissive;","#ifdef DOUBLE_SIDED","vLightBack = ( vLightFront + ambientLightColor + ambient) * diffuse + emissive;","#endif"].join("\n"),lights_physical_pars_vertex:["#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )","varying vec3 vWorldPosition;","#endif"].join("\n"),lights_physical_vertex:["#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )","vWorldPosition = worldPosition.xyz;","#endif","#ifdef USE_SKINNING","vNormal = normalize( normalMatrix * skinnedNormal.xyz );","vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );","vTangent = normalize( normalMatrix * skinnedTangent.xyz );","#else","vNormal = normalize( normalMatrix * normal );","vTangent = normalize( normalMatrix * tangent.xyz );","#endif","vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );"].join("\n"),lights_physical_pars_fragment:["uniform vec3 ambientLightColor;","#if MAX_DIR_LIGHTS > 0","uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];","uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];","#endif","#if MAX_HEMI_LIGHTS > 0","uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];","#endif","#if MAX_POINT_LIGHTS > 0","uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];","uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];","uniform float pointLightDistance[ MAX_POINT_LIGHTS ];","uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];","#endif","#if MAX_SPOT_LIGHTS > 0","uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];","uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];","uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];","uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];","uniform float spotLightDecayExponent[ MAX_SPOT_LIGHTS ];","#endif","#if MAX_AREA_LIGHTS > 0","uniform vec3 areaLightColor[ MAX_AREA_LIGHTS ];","uniform vec3 areaLightPosition[ MAX_AREA_LIGHTS ];","uniform vec3 areaLightWidth[ MAX_AREA_LIGHTS ];","uniform vec3 areaLightHeight[ MAX_AREA_LIGHTS ];","uniform float areaLightDistance[ MAX_AREA_LIGHTS ];","uniform float areaLightDecayExponent[ MAX_AREA_LIGHTS ];","#endif","#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP )","varying vec3 vWorldPosition;","#endif","#ifdef WRAP_AROUND","uniform vec3 wrapRGB;","#endif","varying vec3 vViewPosition;","varying vec3 vTangent;","varying vec3 vBinormal;","varying vec3 vNormal;","vec3 Fresnel_Schlick_SpecularBlendToWhite(vec3 specularColor, float hDotV) {","float Fc = pow(max( 1.0 - hDotV, 0.0 ), 5.0);","return saturate( 50.0 * average( specularColor ) ) * Fc + (1.0 - Fc) * specularColor;","}","vec3 Fresnel_Schlick_SpecularBlendToWhiteRoughness(vec3 specularColor, float hDotV, float roughness) {","float Fc = pow(max( 1.0 - hDotV, 0.0 ), 5.0) / ( 1.0 + 3.0 * roughness );","return mix( specularColor, vec3( saturate( 50.0 * average( specularColor ) ) ), Fc );","}","float Distribution_GGX( float roughness2, float nDotH ) {","float denom = nDotH * nDotH * (roughness2 - 1.0) + 1.0;","return roughness2 / ( PI * square( denom ) + 0.0000001 );","}","float Distribution_GGXAniso( vec2 anisotropicM, vec2 xyDotH, float nDotH ) {","float anisoTerm = ( xyDotH.x * xyDotH.x / ( anisotropicM.x * anisotropicM.x ) + xyDotH.y * xyDotH.y / ( anisotropicM.y * anisotropicM.y ) + nDotH * nDotH );","return 1.0 / ( PI * anisotropicM.x * anisotropicM.y * anisoTerm * anisoTerm + 0.0000001 );","}","float Visibility_Kelemen( float vDotH ) {","return 1.0 / ( 4.0 * vDotH * vDotH + 0.0000001 );","}","float Visibility_Schlick( float roughness2, float nDotL, float nDotV) {","float termL = (nDotL + sqrt(roughness2 + (1.0 - roughness2) * nDotL * nDotL));","float termV = (nDotV + sqrt(roughness2 + (1.0 - roughness2) * nDotV * nDotV));","return 1.0 / ( abs( termL * termV ) + 0.0000001 );","}","float Diffuse_Lambert() {","return 1.0 / PI;","}","float Diffuse_OrenNayer( float m2, float nDotV, float nDotL, float vDotH ) {","float termA = 1.0 - 0.5 * m2 / (m2 + 0.33);","float Cosri = 2.0 * vDotH - 1.0 - nDotV * nDotL;","float termB = 0.45 * m2 / (m2 + 0.09) * Cosri * ( Cosri >= 0.0 ? min( 1.0, nDotL / nDotV ) : nDotL );","return 1.0 / PI * ( nDotL * termA + termB );","}","mat2 createRotationMat2( float rads) {","float cos_rads = cos( rads );","float sin_rads = sin( rads );","return mat2( vec2( cos_rads, sin_rads ), vec2( -sin_rads, cos_rads ) );","}","vec2 calcAnisotropyUV( float anisotropyLocal) {","float oneMinusAbsAnisotropy = 1.0 - min( abs( anisotropyLocal ) * 0.9, 0.9 );","vec2 anisotropyUV = vec2 ( 1.0 / oneMinusAbsAnisotropy, oneMinusAbsAnisotropy );","if( anisotropy < 0.0 ) {","anisotropyUV.xy = anisotropyUV.yx;","}","return anisotropyUV;","}"].join("\n"),lights_physical_fragment:["mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normal );","#ifdef USE_NORMALMAP","normal = perturbNormal2Arb( -vViewPosition, normal );","#endif","#if defined( USE_BUMPMAP )","normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );","#endif","#ifdef DOUBLE_SIDED","normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );","#endif","#ifdef FALLOFF","vec3 modulatedFalloffColor = falloffColor;","#ifdef USE_FALLOFFMAP","vec4 falloffTexelColor = texelDecode( texture2D( falloffMap, vUvLocal ), ENCODING_sRGB );","modulatedFalloffColor = modulatedFalloffColor * falloffTexelColor.xyz;","#endif","float fm = abs( dot( normal, viewDirection ) );","fm = /*falloffBlendParams.x * fm + falloffBlendParams.y * */ ( fm * fm * ( 3.0 - 2.0 * fm ) );","diffuseColor = mix( modulatedFalloffColor, diffuseColor, fm );","#endif","float nDotV = saturate( dot( normal, viewDirection ) );","float m2 = pow( clamp( roughnessStrength, 0.02, 1.0 ), 4.0 );","float m2ClearCoat = pow( clamp( clearCoatRoughness, 0.02, 1.0 ), 4.0 );","specularColor = mix( specularColor * SPECULAR_COEFF, diffuseColor, metallicStrength );","diffuseColor *= ( 1.0 - metallicStrength );","#ifdef ANISOTROPY","vec2 anisotropicM = calcAnisotropyUV( anisotropyStrength ) * sqrt( m2 );","#ifdef ANISOTROPYROTATION","mat2 anisotropicRotationMatrix = createRotationMat2( anisotropyRotationStrength * 2.0 * PI );","#endif","vec3 anisotropicS = tsb[1];","vec3 anisotropicT = tsb[0];","#endif","vec3 totalLighting = vec3( 0.0 );","#if ( defined( USE_ENVMAP ) || defined( USE_DIFFUSEENVMAP ) ) && defined( PHYSICAL )","{","vec3 worldNormal = vec3( normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz ) );","vec3 worldView = -vec3( normalize( ( vec4( viewDirection, 0.0 ) * viewMatrix ).xyz ) );","vec3 reflectVec = reflect( worldView, worldNormal );","vec3 hVector = normal;//normalize( viewDirection.xyz + lVector.xyz );","float nDotH = saturate( dot( normal, normal ) );","float hDotV = saturate( dot( normal, viewDirection ) );","float nDotL = hDotV;//saturate( dot( normal, lVector ) );","vec3 queryVector = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );","#ifdef DOUBLE_SIDED","queryVector *= ( -1.0 + 2.0 * float( gl_FrontFacing ) );","#endif","vec3 worldEnvNormal = vec3( normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz ) );","worldEnvNormal = vec3( flipEnvMap * worldEnvNormal.x, worldEnvNormal.yz );","#ifdef DOUBLE_SIDED","worldEnvNormal *= ( -1.0 + 2.0 * float( gl_FrontFacing ) );","#endif","vec4 diffuseEnvColor = vec4( 0.0, 0.0, 0.0, 1.0 );","#if defined( USE_DIFFUSEENVMAP )","diffuseEnvColor = texelDecode( textureCube( diffuseEnvMap, worldEnvNormal ), diffuseEnvEncoding );","#elif defined( USE_ENVMAP )","#if defined( TEXTURE_CUBE_LOD_EXT )","diffuseEnvColor = texelDecode( textureCubeLodEXT( envMap, worldEnvNormal, 9.5 ), envEncoding );","#else","diffuseEnvColor = texelDecode( textureCube( envMap, worldEnvNormal, 10.0 ), envEncoding );","#endif","#endif","vec4 specularEnvColor = vec4( 0.0, 0.0, 0.0, 1.0 );","#if defined( USE_ENVMAP )","#if defined( TEXTURE_CUBE_LOD_EXT )","float specularMIPLevel = 9.7925 - 0.5 * log2( 2.0 / ( roughness * roughness + 0.00001 ) - 1.0 );","specularEnvColor = texelDecode( textureCubeLodEXT( envMap, queryVector, specularMIPLevel ), envEncoding );","#else","specularEnvColor = mix( texelDecode( textureCube( envMap, queryVector ), envEncoding ), texelDecode( textureCube( envMap, queryVector, 10.0 ), envEncoding ), roughnessStrength );","#endif","#endif","vec3 specClearCoat = vec3(0, 0, 0);","#if defined( CLEARCOAT ) && defined( USE_ENVMAP )","#if defined( TEXTURE_CUBE_LOD_EXT )","float clearCoatMIPLevel = 9.7925 - 0.5 * log2( 2.0 / ( clearCoatRoughness * clearCoatRoughness + 0.00001 ) - 1.0 );","vec4 specularClearCoatEnvColor = texelDecode( textureCubeLodEXT( envMap, queryVector, clearCoatMIPLevel ), envEncoding );","#else","vec4 specularClearCoatEnvColor = mix( texelDecode( textureCube( envMap, queryVector ), envEncoding ), texelDecode( textureCube( envMap, queryVector, 10.0 ), envEncoding ), clearCoatRoughness );","#endif","vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhiteRoughness( vec3( SPECULAR_COEFF ), nDotL, m2ClearCoat );","specClearCoat = specularClearCoatEnvColor.rgb * fresnelClearCoat;","#endif","vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhiteRoughness( specularColor, nDotL, m2 );","vec3 spec = fresnelColor * specularEnvColor.rgb;","vec3 diff = diffuseColor * diffuseEnvColor.rgb;","vec3 shadingResult = spec + diff;","#ifdef CLEARCOAT","shadingResult = mix( shadingResult, specClearCoat, clearCoat );","#endif","totalLighting += shadingResult;","}","#endif","#if MAX_POINT_LIGHTS > 0","for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );","vec3 lVector = lPosition.xyz + vViewPosition.xyz;","float distanceAttenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );","vec3 incidentLight = pointLightColor[ i ] * distanceAttenuation;","lVector = normalize( lVector );","vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );","float nDotH = saturate( dot( normal, hVector ) );","float nDotL = saturate( dot( normal, lVector ) );","float hDotV = saturate( dot( hVector, viewDirection ) );","#ifdef CLEARCOAT","float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );","float visClearCoat = Visibility_Kelemen( hDotV );","vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );","vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;","#endif","#ifdef ANISOTROPY","vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );","#ifdef ANISOTROPYROTATION","xyDotH = anisotropicRotationMatrix * xyDotH;","#endif","float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );","#else","float d = Distribution_GGX( m2, nDotH );","#endif","float vis = Visibility_Schlick(m2, nDotL, nDotV);","vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );","vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;","vec3 diff = nDotL * Diffuse_Lambert() * diffuseColor;","#ifdef TRANSLUCENCY","diff *= whiteCompliment( translucencyColor.xyz );","#endif","vec3 shadingResult = spec + diff;","#ifdef CLEARCOAT","shadingResult = mix( shadingResult, specClearCoat, clearCoat );","#endif","totalLighting += incidentLight * shadingResult;","#ifdef TRANSLUCENCY","float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );","float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );","totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;","#endif","}","#endif","#if MAX_SPOT_LIGHTS > 0","for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );","vec3 lVector = lPosition.xyz + vViewPosition.xyz;","float distanceAttenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );","vec3 incidentLight = spotLightColor[ i ] * distanceAttenuation;","lVector = normalize( lVector );","float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );","if ( spotEffect > spotLightAngleCos[ i ] ) {","spotEffect = pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] );","incidentLight *= spotEffect;","vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );","float nDotH = saturate( dot( normal, hVector ) );","float nDotL = saturate( dot( normal, lVector ) );","float hDotV = saturate( dot( hVector, viewDirection ) );","#ifdef CLEARCOAT","float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );","float visClearCoat = Visibility_Kelemen( hDotV );","vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );","vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;","#endif","#ifdef ANISOTROPY","vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );","#ifdef ANISOTROPYROTATION","xyDotH = anisotropicRotationMatrix * xyDotH;","#endif","float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );","#else","float d = Distribution_GGX( m2, nDotH );","#endif","float vis = Visibility_Schlick(m2, nDotL, nDotV);","vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );","vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;","vec3 diff = nDotL * Diffuse_Lambert() * diffuseColor;","#ifdef TRANSLUCENCY","diff *= whiteCompliment( translucencyColor.xyz );","#endif","vec3 shadingResult = spec + diff;","#ifdef CLEARCOAT","shadingResult = mix( shadingResult, specClearCoat, clearCoat );","#endif","totalLighting += incidentLight * shadingResult;","#ifdef TRANSLUCENCY","float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );","float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );","totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;","#endif","}","}","#endif","#if MAX_DIR_LIGHTS > 0","for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {","vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );","vec3 lVector = normalize( lDirection.xyz );","vec3 incidentLight = directionalLightColor[ i ];","vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );","float nDotH = saturate( dot( normal, hVector ) );","float nDotL = saturate( dot( normal, lVector ) );","float hDotV = saturate( dot( hVector, viewDirection ) );","#ifdef CLEARCOAT","float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );","float visClearCoat = Visibility_Kelemen( hDotV );","vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );","vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;","#endif","#ifdef ANISOTROPY","vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );","#ifdef ANISOTROPYROTATION","xyDotH = anisotropicRotationMatrix * xyDotH;","#endif","float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );","#else","float d = Distribution_GGX( m2, nDotH );","#endif","float vis = Visibility_Schlick(m2, nDotL, nDotV);","vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );","vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;","vec3 diff = nDotL * Diffuse_Lambert() * diffuseColor;","#ifdef TRANSLUCENCY","diff *= whiteCompliment( translucencyColor.xyz );","#endif","vec3 shadingResult = spec + diff;","#ifdef CLEARCOAT","shadingResult = mix( shadingResult, specClearCoat, clearCoat );","#endif","totalLighting += incidentLight * shadingResult;","#ifdef TRANSLUCENCY","float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );","float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );","totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;","#endif","}","#endif","#if MAX_HEMI_LIGHTS > 0","for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {","vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );","vec3 lVector = normalize( lDirection.xyz );","float nDotL = dot( normal, lVector );","vec3 hemiColor = ( PI / 2.0 ) * ( ( 1.0 + nDotL ) * hemisphereLightSkyColor[ i ] + ( 1.0 - nDotL ) * hemisphereLightGroundColor[ i ] );","totalLighting += diffuseColor * hemiColor;","}","#endif","#if MAX_AREA_LIGHTS > 0","for( int i = 0; i < MAX_AREA_LIGHTS; i ++ ) {","vec3 lPosition = ( viewMatrix * vec4( areaLightPosition[ i ], 1.0 ) ).xyz;","vec3 width = areaLightWidth[ i ];","vec3 height = areaLightHeight[ i ];","vec3 up = normalize( ( viewMatrix * vec4( height, 0.0 ) ).xyz );","vec3 right = normalize( ( viewMatrix * vec4( width, 0.0 ) ).xyz );","vec3 pnormal = normalize( cross( right, up ) );","float widthScalar = length( width );","float heightScalar = length( height );","vec3 projection = projectOnPlane( -vViewPosition.xyz, lPosition, pnormal );","vec3 dir = projection - lPosition;","vec2 diagonal = vec2( dot( dir, right ), dot( dir, up ) );","vec2 nearest2D = vec2( clamp( diagonal.x, -widthScalar, widthScalar ), clamp( diagonal.y, -heightScalar, heightScalar ) );","vec3 nearestPointInside = lPosition + ( right *nearest2D.x + up * nearest2D.y );","vec3 lVector = ( nearestPointInside + vViewPosition.xyz );","float distanceAttenuation = calcLightAttenuation( length( lVector ), areaLightDistance[ i ], areaLightDecayExponent[i] );","lVector = normalize( lVector );","vec3 incidentLight = areaLightColor[ i ] * distanceAttenuation * 0.01;","float nDotLDiffuse = saturate( dot( normal, lVector ) );","vec3 diff = Diffuse_Lambert() * diffuseColor * widthScalar * heightScalar;","vec3 viewReflection = reflect( viewDirection.xyz, normal );","vec3 reflectionLightPlaneIntersection = linePlaneIntersect( -vViewPosition.xyz, viewReflection, lPosition, pnormal );","float specAngle = dot( viewReflection, pnormal );","if ( specAngle < 0.0 ) {","vec3 dirSpec = reflectionLightPlaneIntersection - lPosition;","vec2 dirSpec2D = vec2( dot( dirSpec, right ), dot( dirSpec, up ) );","vec2 nearestSpec2D = vec2( clamp( dirSpec2D.x, -widthScalar, widthScalar ), clamp( dirSpec2D.y, -heightScalar, heightScalar ) );","lVector = normalize( lPosition + ( right *nearestSpec2D.x + up * nearestSpec2D.y ) + vViewPosition.xyz );","} else { ","lVector = vec3( 0 );","}","vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );","float nDotH = saturate( dot( normal, hVector ) );","float nDotL = saturate( dot( normal, lVector ) );","float hDotV = saturate( dot( hVector, viewDirection ) );","#ifdef CLEARCOAT","float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );","float visClearCoat = Visibility_Kelemen( hDotV );","vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );","vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;","#endif","#ifdef TRANSLUCENCY","diff *= whiteCompliment( translucencyColor.xyz );","#endif","#ifdef CLEARCOAT","diff = mix( diff, specClearCoat, clearCoat );","#endif","#ifdef ANISOTROPY","vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );","#ifdef ANISOTROPYROTATION","xyDotH = anisotropicRotationMatrix * xyDotH;","#endif","float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );","#else","float d = Distribution_GGX( m2, nDotH );","#endif","float vis = Visibility_Schlick(m2, nDotL, nDotV);","vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );","vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;","totalLighting += incidentLight * spec;","totalLighting += incidentLight * nDotLDiffuse * diff;","#ifdef TRANSLUCENCY","float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );","float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );","totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;","#endif","}","#endif","#ifdef CLEARCOAT","totalLighting += diffuseColor * ( ambientLightColor * ( 1.0 - clearCoat ) );","#else","totalLighting += diffuseColor * ambientLightColor;","#endif","gl_FragColor.xyz += totalLighting;","vec3 emissiveLocal = emissive;","#ifdef USE_EMISSIVEMAP","vec3 emissiveColor = texture2D( emissiveMap, vUv2 ).xyz;","#ifdef GAMMA_INPUT","emissiveColor *= emissiveColor;","#endif","emissiveLocal *= emissiveColor;","#endif","gl_FragColor.xyz += emissiveLocal;","vec3 ambientLocal = ambient;","#ifdef USE_LIGHTMAP","vec3 ambientColor = texture2D( lightMap, vUv2 ).xyz;","#ifdef GAMMA_INPUT","ambientColor *= ambientColor;","#endif","ambientLocal *= ambientColor;","#ifdef CLEARCOAT","ambientLocal *= ( 1.0 - clearCoat );","#endif","#endif","gl_FragColor.xyz += diffuseColor * ambientLocal;"].join("\n"), +lights_phong_pars_vertex:["#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )","varying vec3 vWorldPosition;","#endif"].join("\n"),lights_phong_vertex:["#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )","vWorldPosition = worldPosition.xyz;","#endif"].join("\n"),lights_phong_pars_fragment:["uniform vec3 ambientLightColor;","#if MAX_DIR_LIGHTS > 0","uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];","uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];","#endif","#if MAX_HEMI_LIGHTS > 0","uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];","#endif","#if MAX_POINT_LIGHTS > 0","uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];","uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];","uniform float pointLightDistance[ MAX_POINT_LIGHTS ];","uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];","#endif","#if MAX_SPOT_LIGHTS > 0","uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];","uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];","uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];","uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];","uniform float spotLightDecayExponent[ MAX_SPOT_LIGHTS ];","#endif","#if MAX_AREA_LIGHTS > 0","uniform vec3 areaLightColor[ MAX_AREA_LIGHTS ];","uniform vec3 areaLightPosition[ MAX_AREA_LIGHTS ];","uniform vec3 areaLightWidth[ MAX_AREA_LIGHTS ];","uniform vec3 areaLightHeight[ MAX_AREA_LIGHTS ];","uniform float areaLightDistance[ MAX_AREA_LIGHTS ];","uniform float areaLightDecayExponent[ MAX_AREA_LIGHTS ];","#endif","#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP )","varying vec3 vWorldPosition;","#endif","#ifdef WRAP_AROUND","uniform vec3 wrapRGB;","#endif","varying vec3 vViewPosition;","varying vec3 vNormal;"].join("\n"),lights_phong_fragment:["vec3 normal = normalize( vNormal );","vec3 viewDirection = normalize( vViewPosition );","#ifdef DOUBLE_SIDED","normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );","#endif","#ifdef USE_NORMALMAP","normal = perturbNormal2Arb( -vViewPosition, normal );","#elif defined( USE_BUMPMAP )","normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );","#endif","#if MAX_POINT_LIGHTS > 0","vec3 pointDiffuse = vec3( 0.0 );","vec3 pointSpecular = vec3( 0.0 );","for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );","vec3 lVector = lPosition.xyz + vViewPosition.xyz;","float distanceAttenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );","lVector = normalize( lVector );","float dotProduct = dot( normal, lVector );","float pointDiffuseWeight = max( dotProduct, 0.0 );","pointDiffuse += pointLightColor[ i ] * pointDiffuseWeight * distanceAttenuation;","vec3 pointHalfVector = normalize( lVector + viewDirection );","float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );","float pointSpecularWeight = specularStrength * pow( max( pointDotNormalHalf, 0.0 ), shininess );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );","pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * distanceAttenuation * specularNormalization;","}","#endif","#if MAX_SPOT_LIGHTS > 0","vec3 spotDiffuse = vec3( 0.0 );","vec3 spotSpecular = vec3( 0.0 );","for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );","vec3 lVector = lPosition.xyz + vViewPosition.xyz;","float distanceAttenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );","lVector = normalize( lVector );","float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );","if ( spotEffect > spotLightAngleCos[ i ] ) {","spotEffect = pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] );","float dotProduct = dot( normal, lVector );","#ifdef WRAP_AROUND","float spotDiffuseWeightFull = max( dotProduct, 0.0 );","float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );","vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );","#else","float spotDiffuseWeight = max( dotProduct, 0.0 );","#endif","spotDiffuse += spotLightColor[ i ] * spotDiffuseWeight * distanceAttenuation * spotEffect;","vec3 spotHalfVector = normalize( lVector + viewDirection );","float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );","float spotSpecularWeight = specularStrength * pow( max( spotDotNormalHalf, 0.0 ), shininess );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );","spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * distanceAttenuation * specularNormalization * spotEffect;","}","}","#endif","#if MAX_DIR_LIGHTS > 0","vec3 dirDiffuse = vec3( 0.0 );","vec3 dirSpecular = vec3( 0.0 );","for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {","vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );","vec3 dirVector = normalize( lDirection.xyz );","float dotProduct = dot( normal, dirVector );","#ifdef WRAP_AROUND","float dirDiffuseWeightFull = max( dotProduct, 0.0 );","float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );","vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );","#else","float dirDiffuseWeight = max( dotProduct, 0.0 );","#endif","dirDiffuse += directionalLightColor[ i ] * dirDiffuseWeight;","vec3 dirHalfVector = normalize( dirVector + viewDirection );","float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );","float dirSpecularWeight = specularStrength * pow( max( dirDotNormalHalf, 0.0 ), shininess );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );","dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;","}","#endif","#if MAX_HEMI_LIGHTS > 0","vec3 hemiDiffuse = vec3( 0.0 );","vec3 hemiSpecular = vec3( 0.0 );","for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {","vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );","vec3 lVector = normalize( lDirection.xyz );","float dotProduct = dot( normal, lVector );","float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;","vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );","hemiDiffuse += hemiColor;","vec3 hemiHalfVectorSky = normalize( lVector + viewDirection );","float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;","float hemiSpecularWeightSky = specularStrength * pow( max( hemiDotNormalHalfSky, 0.0 ), shininess );","vec3 lVectorGround = -lVector;","vec3 hemiHalfVectorGround = normalize( lVectorGround + viewDirection );","float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;","float hemiSpecularWeightGround = specularStrength * pow( max( hemiDotNormalHalfGround, 0.0 ), shininess );","float dotProductGround = dot( normal, lVectorGround );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );","vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );","hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );","}","#endif","#if MAX_AREA_LIGHTS > 0","vec3 areaDiffuse = vec3( 0.0 );","vec3 areaSpecular = vec3( 0.0 );","for( int i = 0; i < MAX_AREA_LIGHTS; i ++ ) {","vec3 lPosition = ( viewMatrix * vec4( areaLightPosition[ i ], 1.0 ) ).xyz;","vec3 width = areaLightWidth[ i ];","vec3 height = areaLightHeight[ i ];","vec3 up = normalize( ( viewMatrix * vec4( height, 0.0 ) ).xyz );","vec3 right = normalize( ( viewMatrix * vec4( width, 0.0 ) ).xyz );","vec3 pnormal = normalize( cross( right, up ) );","float widthScalar = length( width );","float heightScalar = length( height );","vec3 projection = projectOnPlane( -vViewPosition.xyz, lPosition, pnormal );","vec3 dir = projection - lPosition;","vec2 diagonal = vec2( dot( dir, right ), dot( dir, up ) );","vec2 nearest2D = vec2( clamp( diagonal.x, -widthScalar, widthScalar ), clamp( diagonal.y, -heightScalar, heightScalar ) );","vec3 nearestPointInside = lPosition + ( right *nearest2D.x + up * nearest2D.y );","vec3 lVector = ( nearestPointInside + vViewPosition.xyz );","float distanceAttenuation = calcLightAttenuation( length( lVector ), areaLightDistance[ i ], areaLightDecayExponent[i] );","lVector = normalize( lVector );","float nDotLDiffuse = saturate( dot( normal, lVector ) );","vec3 viewReflection = reflect( viewDirection.xyz, normal );","vec3 reflectionLightPlaneIntersection = linePlaneIntersect( -vViewPosition.xyz, viewReflection, lPosition, pnormal );","float specAngle = dot( viewReflection, pnormal );","if ( specAngle < 0.0 ) {","vec3 dirSpec = reflectionLightPlaneIntersection - lPosition;","vec2 dirSpec2D = vec2( dot( dirSpec, right ), dot( dirSpec, up ) );","vec2 nearestSpec2D = vec2( clamp( dirSpec2D.x, -widthScalar, widthScalar ), clamp( dirSpec2D.y, -heightScalar, heightScalar ) );","lVector = normalize( lPosition + ( right *nearestSpec2D.x + up * nearestSpec2D.y ) + vViewPosition.xyz );","} else { ","lVector = vec3( 0 );","}","float dotProduct = nDotLDiffuse;","float areaDiffuseWeight = max( dotProduct, 0.0 );","areaDiffuse += areaLightColor[ i ] * areaDiffuseWeight * distanceAttenuation * widthScalar * heightScalar * 0.01;","vec3 areaHalfVector = normalize( lVector + viewDirection );","float areaDotNormalHalf = max( dot( normal, areaHalfVector ), 0.0 );","float areaSpecularWeight = specularStrength * pow( max( areaDotNormalHalf, 0.0 ), shininess );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, areaHalfVector ), 0.0 ), 5.0 );","areaSpecular += schlick * areaLightColor[ i ] * areaSpecularWeight * areaDiffuseWeight * distanceAttenuation * specularNormalization * 0.01;","}","#endif","vec3 totalDiffuse = vec3( 0.0 );","vec3 totalSpecular = vec3( 0.0 );","#if MAX_DIR_LIGHTS > 0","totalDiffuse += dirDiffuse;","totalSpecular += dirSpecular;","#endif","#if MAX_HEMI_LIGHTS > 0","totalDiffuse += hemiDiffuse;","totalSpecular += hemiSpecular;","#endif","#if MAX_POINT_LIGHTS > 0","totalDiffuse += pointDiffuse;","totalSpecular += pointSpecular;","#endif","#if MAX_SPOT_LIGHTS > 0","totalDiffuse += spotDiffuse;","totalSpecular += spotSpecular;","#endif","#if MAX_AREA_LIGHTS > 0","totalDiffuse += areaDiffuse;","totalSpecular += areaSpecular;","#endif","vec3 ambientLocal = ambient;","#ifdef USE_LIGHTMAP","vec3 ambientColor = texture2D( lightMap, vUv2 ).xyz;","#ifdef GAMMA_INPUT","ambientColor *= ambientColor;","#endif","ambientLocal *= ambientColor;","#endif","gl_FragColor.xyz = diffuseColor * ( totalDiffuse + ambientLightColor + ambientLocal ) + totalSpecular;","vec3 emissiveLocal = emissive;","#ifdef USE_EMISSIVEMAP","vec3 emissiveColor = texture2D( emissiveMap, vUv2 ).xyz;","#ifdef GAMMA_INPUT","emissiveColor *= emissiveColor;","#endif","emissiveLocal *= emissiveColor;","#endif","gl_FragColor.xyz += emissiveLocal.xyz;"].join("\n"),color_pars_fragment:["#ifdef USE_COLOR","varying vec3 vColor;","#endif"].join("\n"),color_fragment:["#ifdef USE_COLOR","gl_FragColor = gl_FragColor * vec4( vColor, 1.0 );","#endif"].join("\n"),color_pars_vertex:["#ifdef USE_COLOR","varying vec3 vColor;","#endif"].join("\n"),color_vertex:["#ifdef USE_COLOR","#ifdef GAMMA_INPUT","vColor = color * color;","#else","vColor = color;","#endif","#endif"].join("\n"),skinning_pars_vertex:["#ifdef USE_SKINNING","#ifdef BONE_TEXTURE","uniform sampler2D boneTexture;","uniform int boneTextureWidth;","uniform int boneTextureHeight;","mat4 getBoneMatrix( const float i ) {","float j = i * 4.0;","float x = mod( j, float( boneTextureWidth ) );","float y = floor( j / float( boneTextureWidth ) );","float dx = 1.0 / float( boneTextureWidth );","float dy = 1.0 / float( boneTextureHeight );","y = dy * ( y + 0.5 );","vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );","vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );","vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );","vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );","mat4 bone = mat4( v1, v2, v3, v4 );","return bone;","}","#else","uniform mat4 boneGlobalMatrices[ MAX_BONES ];","mat4 getBoneMatrix( const float i ) {","mat4 bone = boneGlobalMatrices[ int(i) ];","return bone;","}","#endif","#endif"].join("\n"),skinbase_vertex:["#ifdef USE_SKINNING","mat4 boneMatX = getBoneMatrix( skinIndex.x );","mat4 boneMatY = getBoneMatrix( skinIndex.y );","mat4 boneMatZ = getBoneMatrix( skinIndex.z );","mat4 boneMatW = getBoneMatrix( skinIndex.w );","#endif"].join("\n"),skinning_vertex:["#ifdef USE_SKINNING","#ifdef USE_MORPHTARGETS","vec4 skinVertex = vec4( morphed, 1.0 );","#else","vec4 skinVertex = vec4( position, 1.0 );","#endif","vec4 skinned = boneMatX * skinVertex * skinWeight.x;","skinned += boneMatY * skinVertex * skinWeight.y;","skinned += boneMatZ * skinVertex * skinWeight.z;","skinned += boneMatW * skinVertex * skinWeight.w;","#endif"].join("\n"),morphtarget_pars_vertex:["#ifdef USE_MORPHTARGETS","#ifndef USE_MORPHNORMALS","uniform float morphTargetInfluences[ 8 ];","#else","uniform float morphTargetInfluences[ 4 ];","#endif","#endif"].join("\n"),morphtarget_vertex:["#ifdef USE_MORPHTARGETS","vec3 morphed = vec3( 0.0 );","morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];","morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];","morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];","morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];","#ifndef USE_MORPHNORMALS","morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];","morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];","morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];","morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];","#endif","morphed += position;","#endif"].join("\n"),default_vertex:["vec4 mvPosition;","#ifdef USE_SKINNING","mvPosition = modelViewMatrix * skinned;","#endif","#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )","mvPosition = modelViewMatrix * vec4( morphed, 1.0 );","#endif","#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )","mvPosition = modelViewMatrix * vec4( position, 1.0 );","#endif","gl_Position = projectionMatrix * mvPosition;"].join("\n"),morphnormal_vertex:["#ifdef USE_MORPHNORMALS","vec3 morphedNormal = vec3( 0.0 );","morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];","morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];","morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];","morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];","morphedNormal += normal;","#endif"].join("\n"),skinnormal_vertex:["#ifdef USE_SKINNING","mat4 skinMatrix = skinWeight.x * boneMatX;","skinMatrix += skinWeight.y * boneMatY;","#ifdef USE_MORPHNORMALS","vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );","#else","vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );","#endif","#endif"].join("\n"),defaultnormal_vertex:["vec3 objectNormal;","#ifdef USE_SKINNING","objectNormal = skinnedNormal.xyz;","#endif","#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )","objectNormal = morphedNormal;","#endif","#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )","objectNormal = normal;","#endif","#ifdef FLIP_SIDED","objectNormal = -objectNormal;","#endif","vec3 transformedNormal = normalMatrix * objectNormal;"].join("\n"),shadowmap_pars_fragment:["#ifdef USE_SHADOWMAP","uniform sampler2D shadowMap[ MAX_SHADOWS ];","uniform vec2 shadowMapSize[ MAX_SHADOWS ];","uniform float shadowDarkness[ MAX_SHADOWS ];","uniform float shadowBias[ MAX_SHADOWS ];","varying vec4 vShadowCoord[ MAX_SHADOWS ];","float unpackDepth( const vec4 rgba_depth ) {","const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );","float depth = dot( rgba_depth, bit_shift );","return depth;","}","#endif"].join("\n"),shadowmap_fragment:["#ifdef USE_SHADOWMAP","#ifdef SHADOWMAP_DEBUG","vec3 frustumColors[3];","frustumColors[0] = vec3( 1.0, 0.5, 0.0 );","frustumColors[1] = vec3( 0.0, 1.0, 0.8 );","frustumColors[2] = vec3( 0.0, 0.5, 1.0 );","#endif","#ifdef SHADOWMAP_CASCADE","int inFrustumCount = 0;","#endif","float fDepth;","vec3 shadowColor = vec3( 1.0 );","for( int i = 0; i < MAX_SHADOWS; i ++ ) {","vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;","bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );","bool inFrustum = all( inFrustumVec );","#ifdef SHADOWMAP_CASCADE","inFrustumCount += int( inFrustum );","bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );","#else","bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );","#endif","bool frustumTest = all( frustumTestVec );","if ( frustumTest ) {","shadowCoord.z += shadowBias[ i ];","#if defined( SHADOWMAP_TYPE_PCF )","float shadow = 0.0;","const float shadowDelta = 1.0 / 9.0;","float xPixelOffset = 1.0 / shadowMapSize[ i ].x;","float yPixelOffset = 1.0 / shadowMapSize[ i ].y;","float dx0 = -1.25 * xPixelOffset;","float dy0 = -1.25 * yPixelOffset;","float dx1 = 1.25 * xPixelOffset;","float dy1 = 1.25 * yPixelOffset;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );","if ( fDepth < shadowCoord.z ) shadow += shadowDelta;","shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );","#elif defined( SHADOWMAP_TYPE_PCF_SOFT )","float shadow = 0.0;","float xPixelOffset = 1.0 / shadowMapSize[ i ].x;","float yPixelOffset = 1.0 / shadowMapSize[ i ].y;","float dx0 = -1.0 * xPixelOffset;","float dy0 = -1.0 * yPixelOffset;","float dx1 = 1.0 * xPixelOffset;","float dy1 = 1.0 * yPixelOffset;","mat3 shadowKernel;","mat3 depthKernel;","depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );","depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );","depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );","depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );","depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );","depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );","depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );","depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );","depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );","vec3 shadowZ = vec3( shadowCoord.z );","shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));","shadowKernel[0] *= vec3(0.25);","shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));","shadowKernel[1] *= vec3(0.25);","shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));","shadowKernel[2] *= vec3(0.25);","vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );","shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );","shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );","vec4 shadowValues;","shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );","shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );","shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );","shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );","shadow = dot( shadowValues, vec4( 1.0 ) );","shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );","#else","vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );","float fDepth = unpackDepth( rgbaDepth );","if ( fDepth < shadowCoord.z )","shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );","#endif","}","#ifdef SHADOWMAP_DEBUG","#ifdef SHADOWMAP_CASCADE","if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];","#else","if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];","#endif","#endif","}","#ifdef GAMMA_OUTPUT","shadowColor *= shadowColor;","#endif","gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;","#endif"].join("\n"),shadowmap_pars_vertex:["#ifdef USE_SHADOWMAP","varying vec4 vShadowCoord[ MAX_SHADOWS ];","uniform mat4 shadowMatrix[ MAX_SHADOWS ];","#endif"].join("\n"),shadowmap_vertex:["#ifdef USE_SHADOWMAP","for( int i = 0; i < MAX_SHADOWS; i ++ ) {","vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;","}","#endif"].join("\n"),alphatest_fragment:["#ifdef ALPHATEST","if ( gl_FragColor.a < ALPHATEST ) discard;","#endif"].join("\n"),linear_to_gamma_fragment:["#ifdef GAMMA_OUTPUT","gl_FragColor.xyz = sqrt( gl_FragColor.xyz );","#endif"].join("\n")},e.UniformsUtils={merge:function(a){var b,c,d,e={};for(b=0;b dashSize ) {","discard;","}","gl_FragColor = vec4( diffuse, opacity );",e.ShaderChunk.color_fragment,e.ShaderChunk.fog_fragment,"}"].join("\n")},depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2e3},opacity:{type:"f",value:1}},vertexShader:["void main() {","gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );","}"].join("\n"),fragmentShader:["uniform float mNear;","uniform float mFar;","uniform float opacity;","void main() {","float depth = gl_FragCoord.z / gl_FragCoord.w;","float color = clamp( ( depth - mNear ) / ( mFar - mNear ), 0.0, 1.0 );","gl_FragColor = vec4( vec3( color ), opacity );","}"].join("\n")},normal:{uniforms:{opacity:{type:"f",value:1}},vertexShader:["varying vec3 vNormal;",e.ShaderChunk.common,e.ShaderChunk.morphtarget_pars_vertex,"void main() {","vNormal = normalize( normalMatrix * normal );",e.ShaderChunk.morphtarget_vertex,e.ShaderChunk.default_vertex,"}"].join("\n"),fragmentShader:["uniform float opacity;","varying vec3 vNormal;","void main() {","gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );","}"].join("\n")},normalmap:{uniforms:e.UniformsUtils.merge([e.UniformsLib.fog,e.UniformsLib.lights,e.UniformsLib.shadowmap,{enableAO:{type:"i",value:0},enableDiffuse:{type:"i",value:0},enableSpecular:{type:"i",value:0},enableReflection:{type:"i",value:0},enableDisplacement:{type:"i",value:0},tDisplacement:{type:"t",value:null},tDiffuse:{type:"t",value:null},tCube:{type:"t",value:null},tNormal:{type:"t",value:null},tSpecular:{type:"t",value:null},tAO:{type:"t",value:null},uNormalScale:{type:"v2",value:new e.Vector2(1,1)},uDisplacementBias:{type:"f",value:0},uDisplacementScale:{type:"f",value:1},diffuse:{type:"c",value:new e.Color(16777215)},specular:{type:"c",value:new e.Color(1118481)},ambient:{type:"c",value:new e.Color(16777215)},shininess:{type:"f",value:30},opacity:{type:"f",value:1},useRefract:{type:"i",value:0},refractionRatio:{type:"f",value:.98},reflectivity:{type:"f",value:.5},uOffset:{type:"v2",value:new e.Vector2(0,0)},uRepeat:{type:"v2",value:new e.Vector2(1,1)},wrapRGB:{type:"v3",value:new e.Vector3(1,1,1)}}]),fragmentShader:["uniform vec3 ambient;","uniform vec3 diffuse;","uniform vec3 specular;","uniform float shininess;","uniform float opacity;","uniform bool enableDiffuse;","uniform bool enableSpecular;","uniform bool enableAO;","uniform bool enableReflection;","uniform sampler2D tDiffuse;","uniform sampler2D tNormal;","uniform sampler2D tSpecular;","uniform sampler2D tAO;","uniform samplerCube tCube;","uniform vec2 uNormalScale;","uniform bool useRefract;","uniform float refractionRatio;","uniform float reflectivity;","varying vec3 vTangent;","varying vec3 vBinormal;","varying vec3 vNormal;","varying vec2 vUv;","uniform vec3 ambientLightColor;","#if MAX_DIR_LIGHTS > 0","uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];","uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];","#endif","#if MAX_HEMI_LIGHTS > 0","uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];","uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];","#endif","#if MAX_POINT_LIGHTS > 0","uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];","uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];","uniform float pointLightDistance[ MAX_POINT_LIGHTS ];","#endif","#if MAX_SPOT_LIGHTS > 0","uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];","uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];","uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];","uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];","uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];","#endif","#ifdef WRAP_AROUND","uniform vec3 wrapRGB;","#endif","varying vec3 vWorldPosition;","varying vec3 vViewPosition;",e.ShaderChunk.common,e.ShaderChunk.shadowmap_pars_fragment,e.ShaderChunk.fog_pars_fragment,"void main() {","gl_FragColor = vec4( vec3( 1.0 ), opacity );","vec3 specularTex = vec3( 1.0 );","vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;","normalTex.xy *= uNormalScale;","normalTex = normalize( normalTex );","if( enableDiffuse ) {","#ifdef GAMMA_INPUT","vec4 texelColor = texture2D( tDiffuse, vUv );","texelColor.xyz *= texelColor.xyz;","gl_FragColor = gl_FragColor * texelColor;","#else","gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );","#endif","}","if( enableAO ) {","#ifdef GAMMA_INPUT","vec4 aoColor = texture2D( tAO, vUv );","aoColor.xyz *= aoColor.xyz;","gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;","#else","gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;","#endif","}","if( enableSpecular )","specularTex = texture2D( tSpecular, vUv ).xyz;","mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );","vec3 finalNormal = tsb * normalTex;","#ifdef FLIP_SIDED","finalNormal = -finalNormal;","#endif","vec3 normal = normalize( finalNormal );","vec3 viewDirection = normalize( vViewPosition );","#if MAX_POINT_LIGHTS > 0","vec3 pointDiffuse = vec3( 0.0 );","vec3 pointSpecular = vec3( 0.0 );","for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );","vec3 pointVector = lPosition.xyz + vViewPosition.xyz;","float pointDistance = 1.0;","if ( pointLightDistance[ i ] > 0.0 )","pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );","pointVector = normalize( pointVector );","#ifdef WRAP_AROUND","float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );","float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );","vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );","#else","float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );","#endif","pointDiffuse += pointDistance * pointLightColor[ i ] * diffuse * pointDiffuseWeight;","vec3 pointHalfVector = normalize( pointVector + viewDirection );","float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );","float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );","pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;","}","#endif","#if MAX_SPOT_LIGHTS > 0","vec3 spotDiffuse = vec3( 0.0 );","vec3 spotSpecular = vec3( 0.0 );","for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {","vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );","vec3 spotVector = lPosition.xyz + vViewPosition.xyz;","float spotDistance = 1.0;","if ( spotLightDistance[ i ] > 0.0 )","spotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );","spotVector = normalize( spotVector );","float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );","if ( spotEffect > spotLightAngleCos[ i ] ) {","spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );","#ifdef WRAP_AROUND","float spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );","float spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );","vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );","#else","float spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );","#endif","spotDiffuse += spotDistance * spotLightColor[ i ] * diffuse * spotDiffuseWeight * spotEffect;","vec3 spotHalfVector = normalize( spotVector + viewDirection );","float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );","float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, shininess ), 0.0 );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );","spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;","}","}","#endif","#if MAX_DIR_LIGHTS > 0","vec3 dirDiffuse = vec3( 0.0 );","vec3 dirSpecular = vec3( 0.0 );","for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {","vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );","vec3 dirVector = normalize( lDirection.xyz );","#ifdef WRAP_AROUND","float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );","float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );","vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );","#else","float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );","#endif","dirDiffuse += directionalLightColor[ i ] * diffuse * dirDiffuseWeight;","vec3 dirHalfVector = normalize( dirVector + viewDirection );","float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );","float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, shininess ), 0.0 );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );","dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;","}","#endif","#if MAX_HEMI_LIGHTS > 0","vec3 hemiDiffuse = vec3( 0.0 );","vec3 hemiSpecular = vec3( 0.0 );","for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {","vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );","vec3 lVector = normalize( lDirection.xyz );","float dotProduct = dot( normal, lVector );","float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;","vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );","hemiDiffuse += diffuse * hemiColor;","vec3 hemiHalfVectorSky = normalize( lVector + viewDirection );","float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;","float hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );","vec3 lVectorGround = -lVector;","vec3 hemiHalfVectorGround = normalize( lVectorGround + viewDirection );","float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;","float hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );","float dotProductGround = dot( normal, lVectorGround );","float specularNormalization = ( shininess + 2.0001 ) / 8.0;","vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );","vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );","hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );","}","#endif","vec3 totalDiffuse = vec3( 0.0 );","vec3 totalSpecular = vec3( 0.0 );","#if MAX_DIR_LIGHTS > 0","totalDiffuse += dirDiffuse;","totalSpecular += dirSpecular;","#endif","#if MAX_HEMI_LIGHTS > 0","totalDiffuse += hemiDiffuse;","totalSpecular += hemiSpecular;","#endif","#if MAX_POINT_LIGHTS > 0","totalDiffuse += pointDiffuse;","totalSpecular += pointSpecular;","#endif","#if MAX_SPOT_LIGHTS > 0","totalDiffuse += spotDiffuse;","totalSpecular += spotSpecular;","#endif","#ifdef METAL","gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient + totalSpecular );","#else","gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient ) + totalSpecular;","#endif","if ( enableReflection ) {","vec3 vReflect;","vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );","if ( useRefract ) {","vReflect = refract( cameraToVertex, normal, refractionRatio );","} else {","vReflect = reflect( cameraToVertex, normal );","}","vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );","#ifdef GAMMA_INPUT","cubeColor.xyz *= cubeColor.xyz;","#endif","gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * reflectivity );","}",e.ShaderChunk.shadowmap_fragment,e.ShaderChunk.linear_to_gamma_fragment,e.ShaderChunk.fog_fragment,"}"].join("\n"),vertexShader:["attribute vec4 tangent;","uniform vec2 uOffset;","uniform vec2 uRepeat;","uniform bool enableDisplacement;","#ifdef VERTEX_TEXTURES","uniform sampler2D tDisplacement;","uniform float uDisplacementScale;","uniform float uDisplacementBias;","#endif","varying vec3 vTangent;","varying vec3 vBinormal;","varying vec3 vNormal;","varying vec2 vUv;","varying vec3 vWorldPosition;","varying vec3 vViewPosition;",e.ShaderChunk.common,e.ShaderChunk.skinning_pars_vertex,e.ShaderChunk.shadowmap_pars_vertex,"void main() {",e.ShaderChunk.skinbase_vertex,e.ShaderChunk.skinnormal_vertex,"#ifdef USE_SKINNING","vNormal = normalize( normalMatrix * skinnedNormal.xyz );","vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );","vTangent = normalize( normalMatrix * skinnedTangent.xyz );","#else","vNormal = normalize( normalMatrix * normal );","vTangent = normalize( normalMatrix * tangent.xyz );","#endif","vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );","vUv = uv * uRepeat + uOffset;","vec3 displacedPosition;","#ifdef VERTEX_TEXTURES","if ( enableDisplacement ) {","vec3 dv = texture2D( tDisplacement, uv ).xyz;","float df = uDisplacementScale * dv.x + uDisplacementBias;","displacedPosition = position + normalize( normal ) * df;","} else {","#ifdef USE_SKINNING","vec4 skinVertex = vec4( position, 1.0 );","vec4 skinned = boneMatX * skinVertex * skinWeight.x;","skinned += boneMatY * skinVertex * skinWeight.y;","displacedPosition = skinned.xyz;","#else","displacedPosition = position;","#endif","}","#else","#ifdef USE_SKINNING","vec4 skinVertex = vec4( position, 1.0 );","vec4 skinned = boneMatX * skinVertex * skinWeight.x;","skinned += boneMatY * skinVertex * skinWeight.y;","displacedPosition = skinned.xyz;","#else","displacedPosition = position;","#endif","#endif","vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );","vec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );","gl_Position = projectionMatrix * mvPosition;","vWorldPosition = worldPosition.xyz;","vViewPosition = -mvPosition.xyz;","#ifdef USE_SHADOWMAP","for( int i = 0; i < MAX_SHADOWS; i ++ ) {","vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;","}","#endif","}"].join("\n")},cube:{uniforms:{tCube:{type:"t",value:null},tFlip:{type:"f",value:-1},tEncoding:{type:"i",value:0},blurring:{type:"f",value:0}},vertexShader:["varying vec3 vWorldPosition;","void main() {","vec4 worldPosition = modelMatrix * vec4( position, 1.0 );","vWorldPosition = worldPosition.xyz;","gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );","}"].join("\n"),fragmentShader:["#ifdef TEXTURE_CUBE_LOD_EXT","#extension GL_EXT_shader_texture_lod : enable","#endif",e.ShaderChunk.common,"uniform samplerCube tCube;","uniform float tFlip;","uniform int tEncoding;","uniform float blurring;","varying vec3 vWorldPosition;","void main() {","vec3 queryVector = vec3( tFlip * vWorldPosition.x, vWorldPosition.yz );","#if defined( TEXTURE_CUBE_LOD_EXT )","vec4 color = textureCubeLodEXT( tCube, queryVector, blurring );","#else","vec4 color = textureCube( tCube, queryVector );","#endif","color = texelDecode( color, tEncoding );","#ifdef GAMMA_OUTPUT","color.xyz = sqrt( color.xyz );","#endif","gl_FragColor = color;","}"].join("\n")},depthRGBA:{uniforms:{},vertexShader:[e.ShaderChunk.common,e.ShaderChunk.morphtarget_pars_vertex,e.ShaderChunk.skinning_pars_vertex,"void main() {",e.ShaderChunk.skinbase_vertex,e.ShaderChunk.morphtarget_vertex,e.ShaderChunk.skinning_vertex,e.ShaderChunk.default_vertex,"}"].join("\n"),fragmentShader:["vec4 pack_depth( const float depth ) {"," const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );"," const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );"," vec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );"," res -= res.xxyz * bit_mask;"," return res;","}","void main() {","gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );","}"].join("\n")},linearDepthRGBA:{uniforms:{zNear:{type:"f",value:.5},zFar:{type:"f",value:1e3}},vertexShader:[e.ShaderChunk.common,e.ShaderChunk.morphtarget_pars_vertex,e.ShaderChunk.skinning_pars_vertex,"varying vec3 vViewPosition;","void main() {",e.ShaderChunk.skinbase_vertex,e.ShaderChunk.morphtarget_vertex,e.ShaderChunk.skinning_vertex,e.ShaderChunk.default_vertex,"vViewPosition = -mvPosition.xyz;","}"].join("\n"),fragmentShader:["uniform float zNear;","uniform float zFar;","varying vec3 vViewPosition;","vec4 pack_depth( const float depth ) {"," const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );"," const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );"," vec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );"," res -= res.xxyz * bit_mask;"," return res;","}","void main() {","gl_FragColor = pack_depth( clamp( ( vViewPosition.z - zNear ) / ( zFar - zNear ), 0.0, 1.0 ) );","}"].join("\n")}},e.WebGLRenderer=function(a){function b(a){a.__webglVertexBuffer=Ka.createBuffer(),a.__webglColorBuffer=Ka.createBuffer(),Ra.info.memory.geometries++}function c(a){a.__webglVertexBuffer=Ka.createBuffer(),a.__webglColorBuffer=Ka.createBuffer(),a.__webglLineDistanceBuffer=Ka.createBuffer(),Ra.info.memory.geometries++}function f(a){a.__webglVertexBuffer=Ka.createBuffer(),a.__webglNormalBuffer=Ka.createBuffer(),a.__webglTangentBuffer=Ka.createBuffer(),a.__webglColorBuffer=Ka.createBuffer(),a.__webglUVBuffer=Ka.createBuffer(),a.__webglUV2Buffer=Ka.createBuffer(),a.__webglSkinIndicesBuffer=Ka.createBuffer(),a.__webglSkinWeightsBuffer=Ka.createBuffer(),a.__webglFaceBuffer=Ka.createBuffer(),a.__webglLineBuffer=Ka.createBuffer();var b,c;if(a.numMorphTargets)for(a.__webglMorphTargetsBuffers=[],b=0,c=a.numMorphTargets;c>b;b++)a.__webglMorphTargetsBuffers.push(Ka.createBuffer());if(a.numMorphNormals)for(a.__webglMorphNormalsBuffers=[],b=0,c=a.numMorphNormals;c>b;b++)a.__webglMorphNormalsBuffers.push(Ka.createBuffer());Ra.info.memory.geometries++}function g(a,b){var c=a.vertices.length,d=b.material;if(d.attributes){void 0===a.__webglCustomAttributesList&&(a.__webglCustomAttributesList=[]);for(var e in d.attributes){var f=d.attributes[e];if(!f.__webglInitialized||f.createUniqueBuffers){f.__webglInitialized=!0;var g=1;"v2"===f.type?g=2:"v3"===f.type?g=3:"v4"===f.type?g=4:"c"===f.type&&(g=3),f.size=g,f.array=new Float32Array(c*g),f.buffer=Ka.createBuffer(),f.buffer.belongsToAttribute=e,f.needsUpdate=!0}a.__webglCustomAttributesList.push(f)}}}function h(a,b){var c=a.vertices.length;a.__vertexArray=new Float32Array(3*c),a.__colorArray=new Float32Array(3*c),a.__sortArray=[],a.__webglParticleCount=c,g(a,b)}function i(a,b){var c=a.vertices.length;a.__vertexArray=new Float32Array(3*c),a.__colorArray=new Float32Array(3*c),a.__lineDistanceArray=new Float32Array(1*c),a.__webglLineCount=c,g(a,b)}function j(a,b){var c=b.geometry,d=a.faces3,e=3*d.length,f=1*d.length,g=3*d.length,h=k(b,a),i=o(h),j=m(h),l=n(h);a.__vertexArray=new Float32Array(3*e),j&&(a.__normalArray=new Float32Array(3*e)),c.hasTangents&&(a.__tangentArray=new Float32Array(4*e)),l&&(a.__colorArray=new Float32Array(3*e)),i&&(c.faceVertexUvs.length>0&&(a.__uvArray=new Float32Array(2*e)),c.faceVertexUvs.length>1&&(a.__uv2Array=new Float32Array(2*e))),b.geometry.skinWeights.length&&b.geometry.skinIndices.length&&(a.__skinIndexArray=new Float32Array(4*e),a.__skinWeightArray=new Float32Array(4*e)),a.__faceArray=new Uint16Array(3*f),a.__lineArray=new Uint16Array(2*g);var p,q;if(a.numMorphTargets)for(a.__morphTargetsArrays=[],p=0,q=a.numMorphTargets;q>p;p++)a.__morphTargetsArrays.push(new Float32Array(3*e));if(a.numMorphNormals)for(a.__morphNormalsArrays=[],p=0,q=a.numMorphNormals;q>p;p++)a.__morphNormalsArrays.push(new Float32Array(3*e));if(a.__webglFaceCount=3*f,a.__webglLineCount=2*g,h.attributes){void 0===a.__webglCustomAttributesList&&(a.__webglCustomAttributesList=[]);for(var r in h.attributes){var s=h.attributes[r],t={};for(var u in s)t[u]=s[u];if(!t.__webglInitialized||t.createUniqueBuffers){t.__webglInitialized=!0;var v=1;"v2"===t.type?v=2:"v3"===t.type?v=3:"v4"===t.type?v=4:"c"===t.type&&(v=3),t.size=v,t.array=new Float32Array(e*v),t.buffer=Ka.createBuffer(),t.buffer.belongsToAttribute=r,s.needsUpdate=!0,t.__original=s}a.__webglCustomAttributesList.push(t)}}a.__inittedArrays=!0}function k(a,b){return a.material instanceof e.MeshFaceMaterial?a.material.materials[b.materialIndex]:a.material}function l(a){return a&&void 0!==a.shading&&a.shading===e.SmoothShading}function m(a){return a instanceof e.MeshBasicMaterial&&!a.envMap||a instanceof e.MeshDepthMaterial?!1:l(a)?e.SmoothShading:e.FlatShading}function n(a){return a.vertexColors?a.vertexColors:!1}function o(a){return a.map||a.opacityMap||a.lightMap||a.emissiveMap||a.bumpMap||a.normalMap||a.specularMap||a.reflectivityMap||a.roughnessMap||a.falloffMap||a.anisotropyMap||a.anisotropyRotationMap||a.metallicMap||a.translucencyMap||a.anisotropy&&0!==a.anisotropy||a instanceof e.ShaderMaterial,!0}function p(a){var b,c,d;for(b in a.attributes)d="index"===b?Ka.ELEMENT_ARRAY_BUFFER:Ka.ARRAY_BUFFER,c=a.attributes[b],c.buffer=Ka.createBuffer(),Ka.bindBuffer(d,c.buffer),Ka.bufferData(d,c.array,Ka.STATIC_DRAW)}function q(a,b,c){var d,e,f,g,h,i,j,k,l,m,n,o,p=a.vertices,q=p.length,r=a.colors,s=r.length,t=a.__vertexArray,u=a.__colorArray,v=a.__sortArray,w=a.verticesNeedUpdate,x=(a.elementsNeedUpdate,a.colorsNeedUpdate),y=a.__webglCustomAttributesList;if(c.sortParticles){for(tb.copy(sb),tb.multiply(c.matrixWorld),d=0;q>d;d++)f=p[d],ub.copy(f),ub.applyProjection(tb),v[d]=[ub.z,d];for(v.sort(z),d=0;q>d;d++)f=p[v[d][1]],g=3*d,t[g]=f.x,t[g+1]=f.y,t[g+2]=f.z;for(e=0;s>e;e++)g=3*e,i=r[v[e][1]],u[g]=i.r,u[g+1]=i.g,u[g+2]=i.b;if(y)for(j=0,k=y.length;k>j;j++)if(o=y[j],void 0===o.boundTo||"vertices"===o.boundTo)if(g=0,m=o.value.length,1===o.size)for(l=0;m>l;l++)h=v[l][1],o.array[l]=o.value[h];else if(2===o.size)for(l=0;m>l;l++)h=v[l][1],n=o.value[h],o.array[g]=n.x,o.array[g+1]=n.y,g+=2;else if(3===o.size)if("c"===o.type)for(l=0;m>l;l++)h=v[l][1],n=o.value[h],o.array[g]=n.r,o.array[g+1]=n.g,o.array[g+2]=n.b,g+=3;else for(l=0;m>l;l++)h=v[l][1],n=o.value[h],o.array[g]=n.x,o.array[g+1]=n.y,o.array[g+2]=n.z,g+=3;else if(4===o.size)for(l=0;m>l;l++)h=v[l][1],n=o.value[h],o.array[g]=n.x,o.array[g+1]=n.y,o.array[g+2]=n.z,o.array[g+3]=n.w,g+=4}else{if(w)for(d=0;q>d;d++)f=p[d],g=3*d,t[g]=f.x,t[g+1]=f.y,t[g+2]=f.z;if(x)for(e=0;s>e;e++)i=r[e],g=3*e,u[g]=i.r,u[g+1]=i.g,u[g+2]=i.b;if(y)for(j=0,k=y.length;k>j;j++)if(o=y[j],o.needsUpdate&&(void 0===o.boundTo||"vertices"===o.boundTo))if(m=o.value.length,g=0,1===o.size)for(l=0;m>l;l++)o.array[l]=o.value[l];else if(2===o.size)for(l=0;m>l;l++)n=o.value[l],o.array[g]=n.x,o.array[g+1]=n.y,g+=2;else if(3===o.size)if("c"===o.type)for(l=0;m>l;l++)n=o.value[l],o.array[g]=n.r,o.array[g+1]=n.g,o.array[g+2]=n.b,g+=3;else for(l=0;m>l;l++)n=o.value[l],o.array[g]=n.x,o.array[g+1]=n.y,o.array[g+2]=n.z,g+=3;else if(4===o.size)for(l=0;m>l;l++)n=o.value[l],o.array[g]=n.x,o.array[g+1]=n.y,o.array[g+2]=n.z,o.array[g+3]=n.w,g+=4}if((w||c.sortParticles)&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglVertexBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,t,b)),(x||c.sortParticles)&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglColorBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,u,b)),y)for(j=0,k=y.length;k>j;j++)o=y[j],(o.needsUpdate||c.sortParticles)&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,o.buffer),Ka.bufferData(Ka.ARRAY_BUFFER,o.array,b))}function r(a,b){var c,d,e,f,g,h,i,j,k,l,m,n,o=a.vertices,p=a.colors,q=a.lineDistances,r=o.length,s=p.length,t=q.length,u=a.__vertexArray,v=a.__colorArray,w=a.__lineDistanceArray,x=a.verticesNeedUpdate,y=a.colorsNeedUpdate,z=a.lineDistancesNeedUpdate,A=a.__webglCustomAttributesList; +if(x){for(c=0;r>c;c++)f=o[c],g=3*c,u[g]=f.x,u[g+1]=f.y,u[g+2]=f.z;Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglVertexBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,u,b)}if(y){for(d=0;s>d;d++)h=p[d],g=3*d,v[g]=h.r,v[g+1]=h.g,v[g+2]=h.b;Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglColorBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,v,b)}if(z){for(e=0;t>e;e++)w[e]=q[e];Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglLineDistanceBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,w,b)}if(A)for(i=0,j=A.length;j>i;i++)if(n=A[i],n.needsUpdate&&(void 0===n.boundTo||"vertices"===n.boundTo)){if(g=0,l=n.value.length,1===n.size)for(k=0;l>k;k++)n.array[k]=n.value[k];else if(2===n.size)for(k=0;l>k;k++)m=n.value[k],n.array[g]=m.x,n.array[g+1]=m.y,g+=2;else if(3===n.size)if("c"===n.type)for(k=0;l>k;k++)m=n.value[k],n.array[g]=m.r,n.array[g+1]=m.g,n.array[g+2]=m.b,g+=3;else for(k=0;l>k;k++)m=n.value[k],n.array[g]=m.x,n.array[g+1]=m.y,n.array[g+2]=m.z,g+=3;else if(4===n.size)for(k=0;l>k;k++)m=n.value[k],n.array[g]=m.x,n.array[g+1]=m.y,n.array[g+2]=m.z,n.array[g+3]=m.w,g+=4;Ka.bindBuffer(Ka.ARRAY_BUFFER,n.buffer),Ka.bufferData(Ka.ARRAY_BUFFER,n.array,b)}}function s(a,b,c,d,f){if(a.__inittedArrays){var g,h,i,j,k,l,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z=m(f),$=n(f),_=o(f),aa=Z===e.SmoothShading,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=a.__vertexArray,pa=a.__uvArray,qa=a.__uv2Array,ra=a.__normalArray,sa=a.__tangentArray,ta=a.__colorArray,ua=a.__skinIndexArray,va=a.__skinWeightArray,wa=a.__morphTargetsArrays,xa=a.__morphNormalsArrays,ya=a.__webglCustomAttributesList,za=a.__faceArray,Aa=a.__lineArray,Ba=b.geometry,Ca=Ba.verticesNeedUpdate,Da=Ba.elementsNeedUpdate,Ea=Ba.uvsNeedUpdate,Fa=Ba.normalsNeedUpdate,Ga=Ba.tangentsNeedUpdate,Ha=Ba.colorsNeedUpdate,Ia=Ba.morphTargetsNeedUpdate,Ja=Ba.vertices,La=a.faces3,Ma=Ba.faces,Na=Ba.faceVertexUvs[0],Oa=Ba.faceVertexUvs[1],Pa=(Ba.colors,Ba.skinIndices),Qa=Ba.skinWeights,Ra=Ba.morphTargets,Sa=Ba.morphNormals;if(Ca){for(g=0,h=La.length;h>g;g++)j=Ma[La[g]],u=Ja[j.a],v=Ja[j.b],w=Ja[j.c],oa[ca]=u.x,oa[ca+1]=u.y,oa[ca+2]=u.z,oa[ca+3]=v.x,oa[ca+4]=v.y,oa[ca+5]=v.z,oa[ca+6]=w.x,oa[ca+7]=w.y,oa[ca+8]=w.z,ca+=9;Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglVertexBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,oa,c)}if(Ia)for(R=0,S=Ra.length;S>R;R++){for(la=0,g=0,h=La.length;h>g;g++)V=La[g],j=Ma[V],u=Ra[R].vertices[j.a],v=Ra[R].vertices[j.b],w=Ra[R].vertices[j.c],T=wa[R],T[la]=u.x,T[la+1]=u.y,T[la+2]=u.z,T[la+3]=v.x,T[la+4]=v.y,T[la+5]=v.z,T[la+6]=w.x,T[la+7]=w.y,T[la+8]=w.z,f.morphNormals&&(aa?(W=Sa[R].vertexNormals[V],A=W.a,B=W.b,C=W.c):(A=Sa[R].faceNormals[V],B=A,C=A),U=xa[R],U[la]=A.x,U[la+1]=A.y,U[la+2]=A.z,U[la+3]=B.x,U[la+4]=B.y,U[la+5]=B.z,U[la+6]=C.x,U[la+7]=C.y,U[la+8]=C.z),la+=9;Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglMorphTargetsBuffers[R]),Ka.bufferData(Ka.ARRAY_BUFFER,wa[R],c),f.morphNormals&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglMorphNormalsBuffers[R]),Ka.bufferData(Ka.ARRAY_BUFFER,xa[R],c))}if(Qa.length){for(g=0,h=La.length;h>g;g++)j=Ma[La[g]],G=Qa[j.a],H=Qa[j.b],I=Qa[j.c],va[ka]=G.x,va[ka+1]=G.y,va[ka+2]=G.z,va[ka+3]=G.w,va[ka+4]=H.x,va[ka+5]=H.y,va[ka+6]=H.z,va[ka+7]=H.w,va[ka+8]=I.x,va[ka+9]=I.y,va[ka+10]=I.z,va[ka+11]=I.w,J=Pa[j.a],K=Pa[j.b],L=Pa[j.c],ua[ka]=J.x,ua[ka+1]=J.y,ua[ka+2]=J.z,ua[ka+3]=J.w,ua[ka+4]=K.x,ua[ka+5]=K.y,ua[ka+6]=K.z,ua[ka+7]=K.w,ua[ka+8]=L.x,ua[ka+9]=L.y,ua[ka+10]=L.z,ua[ka+11]=L.w,ka+=12;ka>0&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglSkinIndicesBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,ua,c),Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglSkinWeightsBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,va,c))}if(Ha&&$){for(g=0,h=La.length;h>g;g++)j=Ma[La[g]],p=j.vertexColors,q=j.color,3===p.length&&$===e.VertexColors?(D=p[0],E=p[1],F=p[2]):(D=q,E=q,F=q),ta[ja]=D.r,ta[ja+1]=D.g,ta[ja+2]=D.b,ta[ja+3]=E.r,ta[ja+4]=E.g,ta[ja+5]=E.b,ta[ja+6]=F.r,ta[ja+7]=F.g,ta[ja+8]=F.b,ja+=9;ja>0&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglColorBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,ta,c))}if(Ga&&Ba.hasTangents){var Ta=new e.Vector3(0,0,0);for(g=0,h=La.length;h>g;g++)j=Ma[La[g]],r=j.vertexTangents,x=r[0]||Ta,y=r[1]||Ta,z=r[2]||Ta,sa[ha]=x.x,sa[ha+1]=x.y,sa[ha+2]=x.z,sa[ha+3]=x.w,sa[ha+4]=y.x,sa[ha+5]=y.y,sa[ha+6]=y.z,sa[ha+7]=y.w,sa[ha+8]=z.x,sa[ha+9]=z.y,sa[ha+10]=z.z,sa[ha+11]=z.w,ha+=12;Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglTangentBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,sa,c)}if(Fa&&Z){for(g=0,h=La.length;h>g;g++)if(j=Ma[La[g]],k=j.vertexNormals,l=j.normal,3===k.length&&aa)for(M=0;3>M;M++)O=k[M],ra[ga]=O.x,ra[ga+1]=O.y,ra[ga+2]=O.z,ga+=3;else for(M=0;3>M;M++)ra[ga]=l.x,ra[ga+1]=l.y,ra[ga+2]=l.z,ga+=3;Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglNormalBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,ra,c)}if(Ea&&Na&&_){for(g=0,h=La.length;h>g;g++)if(i=La[g],s=Na[i],void 0!==s)for(M=0;3>M;M++)P=s[M],pa[da]=P.x,pa[da+1]=P.y,da+=2;da>0&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglUVBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,pa,c))}if(Ea&&Oa&&_){for(g=0,h=La.length;h>g;g++)if(i=La[g],t=Oa[i],void 0!==t)for(M=0;3>M;M++)Q=t[M],qa[ea]=Q.x,qa[ea+1]=Q.y,ea+=2;ea>0&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglUV2Buffer),Ka.bufferData(Ka.ARRAY_BUFFER,qa,c))}if(Da){for(g=0,h=La.length;h>g;g++)za[fa]=ba,za[fa+1]=ba+1,za[fa+2]=ba+2,fa+=3,Aa[ia]=ba,Aa[ia+1]=ba+1,Aa[ia+2]=ba,Aa[ia+3]=ba+2,Aa[ia+4]=ba+1,Aa[ia+5]=ba+2,ia+=6,ba+=3;Ka.bindBuffer(Ka.ELEMENT_ARRAY_BUFFER,a.__webglFaceBuffer),Ka.bufferData(Ka.ELEMENT_ARRAY_BUFFER,za,c),Ka.bindBuffer(Ka.ELEMENT_ARRAY_BUFFER,a.__webglLineBuffer),Ka.bufferData(Ka.ELEMENT_ARRAY_BUFFER,Aa,c)}if(ya)for(M=0,N=ya.length;N>M;M++)if(Y=ya[M],Y.__original.needsUpdate){if(ma=0,na=0,1===Y.size){if(void 0===Y.boundTo||"vertices"===Y.boundTo)for(g=0,h=La.length;h>g;g++)j=Ma[La[g]],Y.array[ma]=Y.value[j.a],Y.array[ma+1]=Y.value[j.b],Y.array[ma+2]=Y.value[j.c],ma+=3;else if("faces"===Y.boundTo)for(g=0,h=La.length;h>g;g++)X=Y.value[La[g]],Y.array[ma]=X,Y.array[ma+1]=X,Y.array[ma+2]=X,ma+=3}else if(2===Y.size){if(void 0===Y.boundTo||"vertices"===Y.boundTo)for(g=0,h=La.length;h>g;g++)j=Ma[La[g]],u=Y.value[j.a],v=Y.value[j.b],w=Y.value[j.c],Y.array[ma]=u.x,Y.array[ma+1]=u.y,Y.array[ma+2]=v.x,Y.array[ma+3]=v.y,Y.array[ma+4]=w.x,Y.array[ma+5]=w.y,ma+=6;else if("faces"===Y.boundTo)for(g=0,h=La.length;h>g;g++)X=Y.value[La[g]],u=X,v=X,w=X,Y.array[ma]=u.x,Y.array[ma+1]=u.y,Y.array[ma+2]=v.x,Y.array[ma+3]=v.y,Y.array[ma+4]=w.x,Y.array[ma+5]=w.y,ma+=6}else if(3===Y.size){var Ua;if(Ua="c"===Y.type?["r","g","b"]:["x","y","z"],void 0===Y.boundTo||"vertices"===Y.boundTo)for(g=0,h=La.length;h>g;g++)j=Ma[La[g]],u=Y.value[j.a],v=Y.value[j.b],w=Y.value[j.c],Y.array[ma]=u[Ua[0]],Y.array[ma+1]=u[Ua[1]],Y.array[ma+2]=u[Ua[2]],Y.array[ma+3]=v[Ua[0]],Y.array[ma+4]=v[Ua[1]],Y.array[ma+5]=v[Ua[2]],Y.array[ma+6]=w[Ua[0]],Y.array[ma+7]=w[Ua[1]],Y.array[ma+8]=w[Ua[2]],ma+=9;else if("faces"===Y.boundTo)for(g=0,h=La.length;h>g;g++)X=Y.value[La[g]],u=X,v=X,w=X,Y.array[ma]=u[Ua[0]],Y.array[ma+1]=u[Ua[1]],Y.array[ma+2]=u[Ua[2]],Y.array[ma+3]=v[Ua[0]],Y.array[ma+4]=v[Ua[1]],Y.array[ma+5]=v[Ua[2]],Y.array[ma+6]=w[Ua[0]],Y.array[ma+7]=w[Ua[1]],Y.array[ma+8]=w[Ua[2]],ma+=9;else if("faceVertices"===Y.boundTo)for(g=0,h=La.length;h>g;g++)X=Y.value[La[g]],u=X[0],v=X[1],w=X[2],Y.array[ma]=u[Ua[0]],Y.array[ma+1]=u[Ua[1]],Y.array[ma+2]=u[Ua[2]],Y.array[ma+3]=v[Ua[0]],Y.array[ma+4]=v[Ua[1]],Y.array[ma+5]=v[Ua[2]],Y.array[ma+6]=w[Ua[0]],Y.array[ma+7]=w[Ua[1]],Y.array[ma+8]=w[Ua[2]],ma+=9}else if(4===Y.size)if(void 0===Y.boundTo||"vertices"===Y.boundTo)for(g=0,h=La.length;h>g;g++)j=Ma[La[g]],u=Y.value[j.a],v=Y.value[j.b],w=Y.value[j.c],Y.array[ma]=u.x,Y.array[ma+1]=u.y,Y.array[ma+2]=u.z,Y.array[ma+3]=u.w,Y.array[ma+4]=v.x,Y.array[ma+5]=v.y,Y.array[ma+6]=v.z,Y.array[ma+7]=v.w,Y.array[ma+8]=w.x,Y.array[ma+9]=w.y,Y.array[ma+10]=w.z,Y.array[ma+11]=w.w,ma+=12;else if("faces"===Y.boundTo)for(g=0,h=La.length;h>g;g++)X=Y.value[La[g]],u=X,v=X,w=X,Y.array[ma]=u.x,Y.array[ma+1]=u.y,Y.array[ma+2]=u.z,Y.array[ma+3]=u.w,Y.array[ma+4]=v.x,Y.array[ma+5]=v.y,Y.array[ma+6]=v.z,Y.array[ma+7]=v.w,Y.array[ma+8]=w.x,Y.array[ma+9]=w.y,Y.array[ma+10]=w.z,Y.array[ma+11]=w.w,ma+=12;else if("faceVertices"===Y.boundTo)for(g=0,h=La.length;h>g;g++)X=Y.value[La[g]],u=X[0],v=X[1],w=X[2],Y.array[ma]=u.x,Y.array[ma+1]=u.y,Y.array[ma+2]=u.z,Y.array[ma+3]=u.w,Y.array[ma+4]=v.x,Y.array[ma+5]=v.y,Y.array[ma+6]=v.z,Y.array[ma+7]=v.w,Y.array[ma+8]=w.x,Y.array[ma+9]=w.y,Y.array[ma+10]=w.z,Y.array[ma+11]=w.w,ma+=12;Ka.bindBuffer(Ka.ARRAY_BUFFER,Y.buffer),Ka.bufferData(Ka.ARRAY_BUFFER,Y.array,c)}d&&(delete a.__inittedArrays,delete a.__colorArray,delete a.__normalArray,delete a.__tangentArray,delete a.__uvArray,delete a.__uv2Array,delete a.__faceArray,delete a.__vertexArray,delete a.__lineArray,delete a.__skinIndexArray,delete a.__skinWeightArray)}}function t(a,b,c,d){var e,f,g,h;for(f in b)g=b[f],e=c[f],g>=0&&(e?(h=e.itemSize,Ka.bindBuffer(Ka.ARRAY_BUFFER,e.buffer),v(g),Ka.vertexAttribPointer(g,h,Ka.FLOAT,!1,0,d*h*4)):a.defaultAttributeValues&&(2===a.defaultAttributeValues[f].length?Ka.vertexAttrib2fv(g,a.defaultAttributeValues[f]):3===a.defaultAttributeValues[f].length&&Ka.vertexAttrib3fv(g,a.defaultAttributeValues[f])))}function u(a,b){var c,d,e=a.attributes;for(c in e)d=e[c],d.needsUpdate&&("index"===c?(Ka.bindBuffer(Ka.ELEMENT_ARRAY_BUFFER,d.buffer),Ka.bufferData(Ka.ELEMENT_ARRAY_BUFFER,d.array,b)):(Ka.bindBuffer(Ka.ARRAY_BUFFER,d.buffer),Ka.bufferData(Ka.ARRAY_BUFFER,d.array,b)),d.needsUpdate=!1)}function v(a){0===qb[a]&&(Ka.enableVertexAttribArray(a),qb[a]=1)}function w(){for(var a in qb)1===qb[a]&&(Ka.disableVertexAttribArray(a),qb[a]=0)}function x(a,b,c){var d=a.program.attributes;if(-1!==c.morphTargetBase&&d.position>=0?(Ka.bindBuffer(Ka.ARRAY_BUFFER,b.__webglMorphTargetsBuffers[c.morphTargetBase]),v(d.position),Ka.vertexAttribPointer(d.position,3,Ka.FLOAT,!1,0,0)):d.position>=0&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,b.__webglVertexBuffer),v(d.position),Ka.vertexAttribPointer(d.position,3,Ka.FLOAT,!1,0,0)),c.morphTargetForcedOrder.length)for(var e=0,f=c.morphTargetForcedOrder,g=c.morphTargetInfluences;e=0&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,b.__webglMorphTargetsBuffers[f[e]]),v(d["morphTarget"+e]),Ka.vertexAttribPointer(d["morphTarget"+e],3,Ka.FLOAT,!1,0,0)),d["morphNormal"+e]>=0&&a.morphNormals&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,b.__webglMorphNormalsBuffers[f[e]]),v(d["morphNormal"+e]),Ka.vertexAttribPointer(d["morphNormal"+e],3,Ka.FLOAT,!1,0,0)),c.__webglMorphTargetInfluences[e]=g[f[e]],e++;else{var h,i,j=[],g=c.morphTargetInfluences,k=g.length;for(i=0;k>i;i++)h=g[i],h>0&&j.push([h,i]);j.length>a.numSupportedMorphTargets?(j.sort(z),j.length=a.numSupportedMorphTargets):j.length>a.numSupportedMorphNormals?j.sort(z):0===j.length&&j.push([0,0]);for(var l,e=0;e=0&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,b.__webglMorphTargetsBuffers[l]),v(d["morphTarget"+e]),Ka.vertexAttribPointer(d["morphTarget"+e],3,Ka.FLOAT,!1,0,0)),d["morphNormal"+e]>=0&&a.morphNormals&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,b.__webglMorphNormalsBuffers[l]),v(d["morphNormal"+e]),Ka.vertexAttribPointer(d["morphNormal"+e],3,Ka.FLOAT,!1,0,0)),c.__webglMorphTargetInfluences[e]=g[l]):c.__webglMorphTargetInfluences[e]=0,e++}null!==a.program.uniforms.morphTargetInfluences&&Ka.uniform1fv(a.program.uniforms.morphTargetInfluences,c.__webglMorphTargetInfluences)}function y(a,b){return a.z!==b.z?b.z-a.z:a.id-b.id}function z(a,b){return b[0]-a[0]}function A(a,b,c){if(a.length)for(var d=0,e=a.length;e>d;d++)Ua=null,Ya=null,ab=-1,eb=-1,fb=-1,$a=-1,_a=-1,Xa=-1,Wa=-1,yb=!0,a[d].render(b,c,ob,pb),Ua=null,Ya=null,ab=-1,eb=-1,fb=-1,$a=-1,_a=-1,Xa=-1,Wa=-1,yb=!0}function B(a,b,c,d,f,g,h,i){var j,k,l,m,n,o,p;b?(n=a.length-1,o=-1,p=-1):(n=0,o=a.length,p=1);for(var q=n;q!==o;q+=p)if(j=a[q],j.render){if(k=j.object,l=j.buffer,i)m=i;else{if(m=j[c],!m)continue;h&&Ra.setBlending(m.blending,m.blendEquation,m.blendSrc,m.blendDst),Ra.setDepthTest(m.depthTest),Ra.setDepthWrite(m.depthWrite),fa(m.polygonOffset,m.polygonOffsetFactor,m.polygonOffsetUnits)}Ra.setMaterialFaces(m),l instanceof e.BufferGeometry?Ra.renderBufferDirect(d,f,g,m,l,k):Ra.renderBuffer(d,f,g,m,l,k)}}function C(a,b,c,d,e,f,g){for(var h,i,j,k=0,l=a.length;l>k;k++)if(h=a[k],i=h.object,i.visible){if(g)j=g;else{if(j=h[b],!j)continue;f&&Ra.setBlending(j.blending,j.blendEquation,j.blendSrc,j.blendDst),Ra.setDepthTest(j.depthTest),Ra.setDepthWrite(j.depthWrite),fa(j.polygonOffset,j.polygonOffsetFactor,j.polygonOffsetUnits)}Ra.renderImmediateObject(c,d,e,j,i)}}function D(a){var b=a.object,c=b.material;c.transparent?(a.transparent=c,a.opaque=null):(a.opaque=c,a.transparent=null)}function E(a){var b=a.object,c=a.buffer,d=b.geometry,f=b.material;if(f instanceof e.MeshFaceMaterial){var g=d instanceof e.BufferGeometry?0:c.materialIndex;f=f.materials[g],f.transparent?(a.transparent=f,a.opaque=null):(a.opaque=f,a.transparent=null)}else f&&(f.transparent?(a.transparent=f,a.opaque=null):(a.opaque=f,a.transparent=null))}function F(a,d){var g,k,l,m;if(void 0===a.__webglInit)if(a.__webglInit=!0,a._modelViewMatrix=new e.Matrix4,a._normalMatrix=new e.Matrix3,void 0!==a.geometry&&void 0===a.geometry.__webglInit&&(a.geometry.__webglInit=!0,a.geometry.addEventListener("dispose",Mb)),k=a.geometry,void 0===k);else if(k instanceof e.BufferGeometry)p(k);else if(a instanceof e.Mesh){l=a.material,void 0===k.geometryGroups&&k.makeGroups(l instanceof e.MeshFaceMaterial);for(g in k.geometryGroups)m=k.geometryGroups[g],m.__webglVertexBuffer||(f(m),j(m,a),k.verticesNeedUpdate=!0,k.morphTargetsNeedUpdate=!0,k.elementsNeedUpdate=!0,k.uvsNeedUpdate=!0,k.normalsNeedUpdate=!0,k.tangentsNeedUpdate=!0,k.colorsNeedUpdate=!0)}else a instanceof e.Line?k.__webglVertexBuffer||(c(k),i(k,a),k.verticesNeedUpdate=!0,k.colorsNeedUpdate=!0,k.lineDistancesNeedUpdate=!0):a instanceof e.ParticleSystem&&(k.__webglVertexBuffer||(b(k),h(k,a),k.verticesNeedUpdate=!0,k.colorsNeedUpdate=!0));if(void 0===a.__webglActive){if(a instanceof e.Mesh){if(k=a.geometry,k instanceof e.BufferGeometry)G(d.__webglObjects,k,a);else if(k instanceof e.Geometry)for(g in k.geometryGroups)m=k.geometryGroups[g],G(d.__webglObjects,m,a)}else a instanceof e.Line||a instanceof e.ParticleSystem?(k=a.geometry,G(d.__webglObjects,k,a)):a instanceof e.ImmediateRenderObject||a.immediateRenderCallback?H(d.__webglObjectsImmediate,a):a instanceof e.Sprite?d.__webglSprites.push(a):a instanceof e.LensFlare&&d.__webglFlares.push(a);a.__webglActive=!0}}function G(a,b,c){a.push({id:null,buffer:b,object:c,opaque:null,transparent:null,z:0})}function H(a,b){a.push({id:null,object:b,opaque:null,transparent:null,z:0})}function I(a){var b,c,d,f=a.geometry;if(f instanceof e.BufferGeometry)u(f,Ka.DYNAMIC_DRAW);else if(a instanceof e.Mesh){for(var g=0,h=f.geometryGroupsList.length;h>g;g++)b=f.geometryGroupsList[g],d=k(a,b),f.buffersNeedUpdate&&j(b,a),c=d.attributes&&J(d),(f.verticesNeedUpdate||f.morphTargetsNeedUpdate||f.elementsNeedUpdate||f.uvsNeedUpdate||f.normalsNeedUpdate||f.colorsNeedUpdate||f.tangentsNeedUpdate||c)&&s(b,a,Ka.DYNAMIC_DRAW,!f.dynamic,d);f.verticesNeedUpdate=!1,f.morphTargetsNeedUpdate=!1,f.elementsNeedUpdate=!1,f.uvsNeedUpdate=!1,f.normalsNeedUpdate=!1,f.colorsNeedUpdate=!1,f.tangentsNeedUpdate=!1,f.buffersNeedUpdate=!1,d.attributes&&K(d)}else a instanceof e.Line?(d=k(a,f),c=d.attributes&&J(d),(f.verticesNeedUpdate||f.colorsNeedUpdate||f.lineDistancesNeedUpdate||c)&&r(f,Ka.DYNAMIC_DRAW),f.verticesNeedUpdate=!1,f.colorsNeedUpdate=!1,f.lineDistancesNeedUpdate=!1,d.attributes&&K(d)):a instanceof e.ParticleSystem&&(d=k(a,f),c=d.attributes&&J(d),(f.verticesNeedUpdate||f.colorsNeedUpdate||a.sortParticles||c)&&q(f,Ka.DYNAMIC_DRAW,a),f.verticesNeedUpdate=!1,f.colorsNeedUpdate=!1,d.attributes&&K(d))}function J(a){for(var b in a.attributes)if(a.attributes[b].needsUpdate)return!0;return!1}function K(a){for(var b in a.attributes)a.attributes[b].needsUpdate=!1}function L(a,b){a instanceof e.Mesh||a instanceof e.ParticleSystem||a instanceof e.Line?M(b.__webglObjects,a):a instanceof e.Sprite?N(b.__webglSprites,a):a instanceof e.LensFlare?N(b.__webglFlares,a):(a instanceof e.ImmediateRenderObject||a.immediateRenderCallback)&&M(b.__webglObjectsImmediate,a),delete a.__webglActive}function M(a,b){for(var c=a.length-1;c>=0;c--)a[c].object===b&&a.splice(c,1)}function N(a,b){for(var c=a.length-1;c>=0;c--)a[c]===b&&a.splice(c,1)}function O(a,b){a.uniforms=e.UniformsUtils.clone(b.uniforms),a.vertexShader=b.vertexShader,a.fragmentShader=b.fragmentShader}function P(a,b,c,d,f){if(Za=0,d.needsUpdate){var g=d.program;Ra.initMaterial(d,b,c,f),d.needsUpdate=!1,g&&Ub(d,g)}d.morphTargets&&(f.__webglMorphTargetInfluences||(f.__webglMorphTargetInfluences=new Float32Array(Ra.maxMorphTargets)));var h=!1,i=d.program,j=i.uniforms,k=d.uniforms;if(i!==Ua&&(Ka.useProgram(i),Ua=i,h=!0),d.id!==Wa&&(Wa=d.id,h=!0),(h||a!==Ya)&&(Ka.uniformMatrix4fv(j.projectionMatrix,!1,a.projectionMatrix.elements),a!==Ya&&(Ya=a)),d.skinning)if(Fb&&f.useVertexTexture){if(null!==j.boneTexture){var l=_();Ka.uniform1i(j.boneTexture,l),Ra.setTexture(f.boneTexture,l)}null!==j.boneTextureWidth&&Ka.uniform1i(j.boneTextureWidth,f.boneTextureWidth),null!==j.boneTextureHeight&&Ka.uniform1i(j.boneTextureHeight,f.boneTextureHeight)}else null!==j.boneGlobalMatrices&&Ka.uniformMatrix4fv(j.boneGlobalMatrices,!1,f.boneMatrices);return h&&(c&&d.fog&&U(k,c),(d instanceof e.MeshPhongMaterial||d instanceof e.MeshLambertMaterial||d instanceof e.MeshPhysicalMaterial||d.lights)&&(yb&&(da(i,b),yb=!1),Y(k,zb)),(d instanceof e.MeshBasicMaterial||d instanceof e.MeshLambertMaterial||d instanceof e.MeshPhysicalMaterial||d instanceof e.MeshPhongMaterial)&&Q(k,d),d instanceof e.LineBasicMaterial?R(k,d):d instanceof e.LineDashedMaterial?(R(k,d),S(k,d)):d instanceof e.ParticleSystemMaterial?T(k,d):d instanceof e.MeshPhongMaterial?V(k,d):d instanceof e.MeshPhysicalMaterial?W(k,d):d instanceof e.MeshLambertMaterial?X(k,d):d instanceof e.MeshDepthMaterial?(k.mNear.value=a.near,k.mFar.value=a.far,k.opacity.value=d.opacity):d instanceof e.MeshNormalMaterial&&(k.opacity.value=d.opacity),f.receiveShadow&&!d._shadowPass&&Z(k,b),aa(i,d.uniformsList),(d instanceof e.ShaderMaterial||d instanceof e.MeshPhongMaterial||d instanceof e.MeshPhysicalMaterial||d.envMap||d.diffuseEnvMap)&&null!==j.cameraPosition&&(ub.setFromMatrixPosition(a.matrixWorld),Ka.uniform3f(j.cameraPosition,ub.x,ub.y,ub.z)),(d instanceof e.MeshPhongMaterial||d instanceof e.MeshLambertMaterial||d instanceof e.MeshPhysicalMaterial||d instanceof e.ShaderMaterial||d.skinning)&&null!==j.viewMatrix&&Ka.uniformMatrix4fv(j.viewMatrix,!1,a.matrixWorldInverse.elements)),$(j,f),null!==j.modelMatrix&&Ka.uniformMatrix4fv(j.modelMatrix,!1,f.matrixWorld.elements),i}function Q(a,b){if(a.opacity.value=b.opacity,a.diffuse.value=b.color,a.map.value=b.map,a.lightMap.value=b.lightMap,a.emissiveMap.value=b.emissiveMap,b.bumpMap&&(a.bumpMap.value=b.bumpMap,a.bumpScale.value=b.bumpScale),b.normalMap&&(a.normalMap.value=b.normalMap,a.normalScale.value.copy(b.normalScale)),b.map){var c=b.map;a.offsetRepeat.value.set(c.offset.x,c.offset.y,c.repeat.x,c.repeat.y),a.gainBrightness.value.set(c.gainPivot,c.gain,c.brightness,c.invert?-1:1)}if(b.specularMap){var d=b.specularMap;a.specularMap.value=d,a.specularOffsetRepeat.value.set(d.offset.x,d.offset.y,d.repeat.x,d.repeat.y),a.specularGainBrightness.value.set(d.gainPivot,d.gain,d.brightness,d.invert?-1:1)}if(b.opacityMap){var f=b.opacityMap;a.opacityMap.value=f,a.opacityOffsetRepeat.value.set(f.offset.x,f.offset.y,f.repeat.x,f.repeat.y),a.opacityGainBrightness.value.set(f.gainPivot,f.gain,f.brightness,f.invert?-1:1)}if(b.bumpMap){var g=b.bumpMap;a.bumpOffsetRepeat.value.set(g.offset.x,g.offset.y,g.repeat.x,g.repeat.y)}if(b.normalMap){var h=b.normalMap;a.normalOffsetRepeat.value.set(h.offset.x,h.offset.y,h.repeat.x,h.repeat.y)}if(b.anisotropyMap){var i=b.anisotropyMap;a.anisotropyOffsetRepeat.value.set(i.offset.x,i.offset.y,i.repeat.x,i.repeat.y),a.anisotropyGainBrightness.value.set(i.gainPivot,i.gain,i.brightness,i.invert?-1:1)}if(b.anisotropyRotationMap){var j=b.anisotropyRotationMap;a.anisotropyRotationOffsetRepeat.value.set(j.offset.x,j.offset.y,j.repeat.x,j.repeat.y),a.anisotropyRotationGainBrightness.value.set(j.gainPivot,j.gain,j.brightness,j.invert?-1:1)}if(b.roughnessMap){var k=b.roughnessMap;a.roughnessOffsetRepeat.value.set(k.offset.x,k.offset.y,k.repeat.x,k.repeat.y),a.roughnessGainBrightness.value.set(k.gainPivot,k.gain,k.brightness,k.invert?-1:1)}if(b.metallicMap){var l=b.metallicMap;a.metallicOffsetRepeat.value.set(l.offset.x,l.offset.y,l.repeat.x,l.repeat.y),a.metallicGainBrightness.value.set(l.gainPivot,l.gain,l.brightness,l.invert?-1:1)}if(b.translucencyMap){var m=b.translucencyMap;a.translucencyMap.value=m}a.envMap.value=b.envMap,a.flipEnvMap.value=b.envMap instanceof e.WebGLRenderTargetCube?1:-1,a.envEncoding.value=b.envMap?b.envMap.encoding:0,a.diffuseEnvMap.value=b.diffuseEnvMap,a.diffuseEnvEncoding.value=b.diffuseEnvMap?b.diffuseEnvMap.encoding:0,a.reflectivity.value=b.reflectivity,a.refractionRatio.value=b.refractionRatio,a.combine.value=b.combine,a.useRefract.value=b.envMap&&b.envMap.mapping instanceof e.CubeRefractionMapping}function R(a,b){a.diffuse.value=b.color,a.opacity.value=b.opacity}function S(a,b){a.dashSize.value=b.dashSize,a.totalSize.value=b.dashSize+b.gapSize,a.scale.value=b.scale}function T(a,b){a.psColor.value=b.color,a.opacity.value=b.opacity,a.size.value=b.size,a.scale.value=Aa.height/2,a.map.value=b.map}function U(a,b){a.fogColor.value=b.color,b instanceof e.Fog?(a.fogNear.value=b.near,a.fogFar.value=b.far):b instanceof e.FogExp2&&(a.fogDensity.value=b.density)}function V(a,b){a.opacityMap.value=b.opacityMap,a.shininess.value=b.shininess,a.ambient.value=b.ambient,a.emissive.value=b.emissive,a.specular.value=b.specular,b.wrapAround&&a.wrapRGB.value.copy(b.wrapRGB)}function W(a,b){a.opacityMap.value=b.opacityMap,a.falloffBlendParams.value=b.falloffBlendParams,a.falloffMap.value=b.falloffMap,a.roughness.value=b.roughness,a.metallic.value=b.metallic,a.clearCoat.value=b.clearCoat,a.clearCoatRoughness.value=b.clearCoatRoughness,a.roughnessMap.value=b.roughnessMap,a.metallicMap.value=b.metallicMap,a.translucencyMap.value=b.translucencyMap,a.translucencyNormalAlpha.value=b.translucencyNormalAlpha,a.translucencyNormalPower.value=b.translucencyNormalPower,a.translucencyViewAlpha.value=b.translucencyViewAlpha,a.translucencyViewPower.value=b.translucencyViewPower,a.anisotropyMap.value=b.anisotropyMap,a.anisotropy.value=b.anisotropy,a.anisotropyRotation.value=b.anisotropyRotation,a.anisotropyRotationMap.value=b.anisotropyRotationMap,a.ambient.value=b.ambient,a.emissive.value=b.emissive,a.falloffColor.value=b.falloffColor,a.specular.value=b.specular,a.translucency.value=b.translucency}function X(a,b){a.ambient.value=b.ambient,a.emissive.value=b.emissive,b.wrapAround&&a.wrapRGB.value.copy(b.wrapRGB)}function Y(a,b){a.ambientLightColor.value=b.ambient,a.directionalLightColor.value=b.directional.colors,a.directionalLightDirection.value=b.directional.positions,a.pointLightColor.value=b.point.colors,a.pointLightPosition.value=b.point.positions,a.pointLightDistance.value=b.point.distances,a.pointLightDecayExponent.value=b.point.decayExponents,a.spotLightColor.value=b.spot.colors,a.spotLightPosition.value=b.spot.positions,a.spotLightDistance.value=b.spot.distances,a.spotLightDecayExponent.value=b.spot.decayExponents,a.spotLightDirection.value=b.spot.directions,a.spotLightAngleCos.value=b.spot.anglesCos,a.spotLightExponent.value=b.spot.exponents,a.hemisphereLightSkyColor.value=b.hemi.skyColors,a.hemisphereLightGroundColor.value=b.hemi.groundColors,a.hemisphereLightDirection.value=b.hemi.positions,a.areaLightColor.value=b.area.colors,a.areaLightPosition.value=b.area.positions,a.areaLightDistance.value=b.area.distances,a.areaLightDecayExponent.value=b.area.decayExponents,a.areaLightWidth.value=b.area.widths,a.areaLightHeight.value=b.area.heights}function Z(a,b){if(a.shadowMatrix)for(var c=0,d=0,f=b.length;f>d;d++){var g=b[d];g.castShadow&&(g instanceof e.SpotLight||g instanceof e.DirectionalLight&&!g.shadowCascade)&&(a.shadowMap.value[c]=g.shadowMap,a.shadowMapSize.value[c]=g.shadowMapSize,a.shadowMatrix.value[c]=g.shadowMatrix,a.shadowDarkness.value[c]=g.shadowDarkness,a.shadowBias.value[c]=g.shadowBias,c++)}}function $(a,b){Ka.uniformMatrix4fv(a.modelViewMatrix,!1,b._modelViewMatrix.elements),a.normalMatrix&&Ka.uniformMatrix3fv(a.normalMatrix,!1,b._normalMatrix.elements)}function _(){var a=Za;return a>=Ab&&e.onwarning("WebGLRenderer: trying to use "+a+" texture units while this GPU supports only "+Ab),Za+=1,a}function aa(a,b){var c,d,f,g,h,i,j,k,l,m,n;for(l=0,m=b.length;m>l;l++)if(g=a.uniforms[b[l][1]])if(c=b[l][0],f=c.type,d=c.value,"i"===f)Ka.uniform1i(g,d);else if("f"===f)Ka.uniform1f(g,d);else if("v2"===f)Ka.uniform2f(g,d.x,d.y);else if("v3"===f)Ka.uniform3f(g,d.x,d.y,d.z);else if("v4"===f)Ka.uniform4f(g,d.x,d.y,d.z,d.w);else if("c"===f)Ka.uniform3f(g,d.r,d.g,d.b);else if("iv1"===f)Ka.uniform1iv(g,d);else if("iv"===f)Ka.uniform3iv(g,d);else if("fv1"===f)Ka.uniform1fv(g,d);else if("fv"===f)Ka.uniform3fv(g,d);else if("v2v"===f){for(void 0===c._array&&(c._array=new Float32Array(2*d.length)),j=0,k=d.length;k>j;j++)n=2*j,c._array[n]=d[j].x,c._array[n+1]=d[j].y;Ka.uniform2fv(g,c._array)}else if("v3v"===f){for(void 0===c._array&&(c._array=new Float32Array(3*d.length)),j=0,k=d.length;k>j;j++)n=3*j,c._array[n]=d[j].x,c._array[n+1]=d[j].y,c._array[n+2]=d[j].z;Ka.uniform3fv(g,c._array)}else if("v4v"===f){for(void 0===c._array&&(c._array=new Float32Array(4*d.length)),j=0,k=d.length;k>j;j++)n=4*j,c._array[n]=d[j].x,c._array[n+1]=d[j].y,c._array[n+2]=d[j].z,c._array[n+3]=d[j].w;Ka.uniform4fv(g,c._array)}else if("m4"===f)void 0===c._array&&(c._array=new Float32Array(16)),d.flattenToArray(c._array),Ka.uniformMatrix4fv(g,!1,c._array);else if("m4v"===f){for(void 0===c._array&&(c._array=new Float32Array(16*d.length)),j=0,k=d.length;k>j;j++)d[j].flattenToArrayOffset(c._array,16*j);Ka.uniformMatrix4fv(g,!1,c._array)}else if("t"===f){if(h=d,i=_(),Ka.uniform1i(g,i),!h)continue;h.image instanceof Array&&6===h.image.length?oa(h,i):h instanceof e.WebGLRenderTargetCube?pa(h,i):Ra.setTexture(h,i)}else if("tv"===f){for(void 0===c._array&&(c._array=[]),j=0,k=c.value.length;k>j;j++)c._array[j]=_();for(Ka.uniform1iv(g,c._array),j=0,k=c.value.length;k>j;j++)h=c.value[j],i=c._array[j],h&&Ra.setTexture(h,i)}else e.onwarning("THREE.WebGLRenderer: Unknown uniform type: "+f)}function ba(a,b){a._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,a.matrixWorld),a._normalMatrix.getNormalMatrix(a._modelViewMatrix)}function ca(a,b,c,d){a[b]=c.r*d,a[b+1]=c.g*d,a[b+2]=c.b*d}function da(a,b){var c,d,f,g,h,i,j,k,l=0,m=0,n=0,o=zb,p=o.directional.colors,q=o.directional.positions,r=o.point.colors,s=o.point.positions,t=o.point.distances,u=o.point.decayExponents,v=o.spot.colors,w=o.spot.positions,x=o.spot.distances,y=o.spot.decayExponents,z=o.spot.directions,A=o.spot.anglesCos,B=o.spot.exponents,C=o.hemi.skyColors,D=o.hemi.groundColors,E=o.hemi.positions,F=o.area.colors,G=o.area.positions,H=o.area.distances,I=o.area.decayExponents,J=o.area.widths,K=o.area.heights,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0;for(c=0,d=b.length;d>c;c++)if(f=b[c],!f.onlyShadow)if(g=f.color,j=f.intensity,k=f.distance,f instanceof e.AmbientLight){if(!f.visible)continue;l+=g.r,m+=g.g,n+=g.b}else if(f instanceof e.DirectionalLight){if(Q+=1,!f.visible)continue;if(xb.setFromMatrixPosition(f.matrixWorld),ub.setFromMatrixPosition(f.target.matrixWorld),xb.sub(ub),xb.normalize(),0===xb.x&&0===xb.y&&0===xb.z)continue;V=3*L,q[V]=xb.x,q[V+1]=xb.y,q[V+2]=xb.z,ca(p,V,g,j),L+=1}else if(f instanceof e.PointLight){if(R+=1,!f.visible)continue;W=3*M,ca(r,W,g,j),ub.setFromMatrixPosition(f.matrixWorld),s[W]=ub.x,s[W+1]=ub.y,s[W+2]=ub.z,t[M]=k,f.physicalFalloff?u[M]=-1:u[M]=0===k?0:f.decayExponent,M+=1}else if(f instanceof e.SpotLight){if(S+=1,!f.visible)continue;X=3*N,ca(v,X,g,j),ub.setFromMatrixPosition(f.matrixWorld),w[X]=ub.x,w[X+1]=ub.y,w[X+2]=ub.z,x[N]=k,f.physicalFalloff?y[M]=-1:y[M]=0===k?0:f.decayExponent,xb.copy(ub),ub.setFromMatrixPosition(f.target.matrixWorld),xb.sub(ub),xb.normalize(),z[X]=xb.x,z[X+1]=xb.y,z[X+2]=xb.z,A[N]=Math.cos(f.angle),B[N]=f.exponent,N+=1}else if(f instanceof e.HemisphereLight){if(T+=1,!f.visible)continue;if(xb.setFromMatrixPosition(f.matrixWorld),xb.normalize(),0===xb.x&&0===xb.y&&0===xb.z)continue;Y=3*O,E[Y]=xb.x,E[Y+1]=xb.y,E[Y+2]=xb.z,h=f.color,i=f.groundColor,ca(C,Y,h,j),ca(D,Y,i,j),O+=1}else if(f instanceof e.AreaLight){if(U+=1,!f.visible)continue;Z=3*P,ca(F,Z,g,j),ub.setFromMatrixPosition(f.matrixWorld),G[Z]=ub.x,G[Z+1]=ub.y,G[Z+2]=ub.z,H[P]=k,I[P]=f.decayExponent,f.matrixWorld.extractBasis(vb,wb,ub),vb.multiplyScalar(f.width),wb.multiplyScalar(f.height),J[Z]=vb.x,J[Z+1]=vb.y,J[Z+2]=vb.z,K[Z]=wb.x,K[Z+1]=wb.y,K[Z+2]=wb.z,P+=1}for(c=3*L,d=Math.max(p.length,3*Q);d>c;c++)p[c]=0;for(c=3*M,d=Math.max(r.length,3*R);d>c;c++)r[c]=0;for(c=3*N,d=Math.max(v.length,3*S);d>c;c++)v[c]=0;for(c=3*O,d=Math.max(C.length,3*T);d>c;c++)C[c]=0;for(c=3*O,d=Math.max(D.length,3*T);d>c;c++)D[c]=0;for(c=3*P,d=Math.max(F.length,3*U);d>c;c++)F[c]=0;o.directional.length=L,o.point.length=M,o.spot.length=N,o.hemi.length=O,o.area.length=P,o.ambient[0]=l,o.ambient[1]=m,o.ambient[2]=n}function ea(a){a!==jb&&(Ka.lineWidth(a),jb=a)}function fa(a,b,c){gb!==a&&(a?Ka.enable(Ka.POLYGON_OFFSET_FILL):Ka.disable(Ka.POLYGON_OFFSET_FILL),gb=a),!a||hb===b&&ib===c||(Ka.polygonOffset(b,c),hb=b,ib=c)}function ga(a){var b,c,d=[];for(var e in a)b=a[e],b!==!1&&(c="#define "+e+" "+b,d.push(c));return d.join("\n")}function ha(a,b,c,d,f,g,h,i){var j,k,l,m,n,o=[],p=[];a?(p.push(a),o.push(a)):(p.push(b),p.push(c));for(l in g)p.push(l),p.push(g[l]),o.push(l),o.push(g[l]);for(j in h)p.push(j),p.push(h[j]),o.push(j),o.push(h[j]);n=p.join();var q=o.join();for(j=0,k=Sa.length;k>j;j++){var r=Sa[j];if(r.code.length===n.length&&r.code===n)return r.usedTimes++,r.program}var s="SHADOWMAP_TYPE_BASIC";h.shadowMapType===e.PCFShadowMap?s="SHADOWMAP_TYPE_PCF":h.shadowMapType===e.PCFSoftShadowMap&&(s="SHADOWMAP_TYPE_PCF_SOFT");var t=ga(g);m=Ka.createProgram();var u=null!==Oa,v=["precision "+Ca+" float;","precision "+Ca+" int;",t,Eb?"#define VERTEX_TEXTURES":"",Ra.gammaInput?"#define GAMMA_INPUT":"",Ra.gammaOutput?"#define GAMMA_OUTPUT":"","#define MAX_DIR_LIGHTS "+h.maxDirLights,"#define MAX_POINT_LIGHTS "+h.maxPointLights,"#define MAX_SPOT_LIGHTS "+h.maxSpotLights,"#define MAX_HEMI_LIGHTS "+h.maxHemiLights,"#define MAX_AREA_LIGHTS "+h.maxAreaLights,"#define MAX_SHADOWS "+h.maxShadows,"#define MAX_BONES "+h.maxBones,h.map?"#define USE_MAP":"",h.opacityMap?"#define USE_OPACITYMAP":"",h.falloffMap?"#define USE_FALLOFFMAP":"",h.translucencyMap?"#define USE_TRANSLUCENCYMAP":"",h.envMap?"#define USE_ENVMAP":"",h.diffuseEnvMap?"#define USE_DIFFUSEENVMAP":"",h.lightMap?"#define USE_LIGHTMAP":"",h.emissiveMap?"#define USE_EMISSIVEMAP":"",h.bumpMap?"#define USE_BUMPMAP":"",h.reflectivityMap?"#define USE_REFLECTIVITYMAP":"",h.roughnessMap?"#define USE_ROUGHNESSMAP":"",h.metallicMap?"#define USE_METALLICMAP":"",h.normalMap?"#define USE_NORMALMAP":"",h.specularMap?"#define USE_SPECULARMAP":"",h.vertexColors?"#define USE_COLOR":"",h.clearCoat?"#define CLEARCOAT":"",h.anisotropy?"#define ANISOTROPY":"",h.anisotropyMap?"#define USE_ANISOTROPYMAP":"",h.anisotropy&&h.anisotropyRotation?"#define ANISOTROPYROTATION":"",h.anisotropy&&h.anisotropyRotationMap?"#define USE_ANISOTROPYROTATIONMAP":"",h.skinning?"#define USE_SKINNING":"",h.useVertexTexture?"#define BONE_TEXTURE":"",h.morphTargets?"#define USE_MORPHTARGETS":"",h.morphNormals?"#define USE_MORPHNORMALS":"",h.wrapAround?"#define WRAP_AROUND":"",h.doubleSided?"#define DOUBLE_SIDED":"",h.flipSided?"#define FLIP_SIDED":"",h.shadowMapEnabled?"#define USE_SHADOWMAP":"",h.shadowMapEnabled?"#define "+s:"",h.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",h.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",h.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","attribute vec2 uv2;","#ifdef USE_COLOR","attribute vec3 color;","#endif","#ifdef USE_MORPHTARGETS","attribute vec3 morphTarget0;","attribute vec3 morphTarget1;","attribute vec3 morphTarget2;","attribute vec3 morphTarget3;","#ifdef USE_MORPHNORMALS","attribute vec3 morphNormal0;","attribute vec3 morphNormal1;","attribute vec3 morphNormal2;","attribute vec3 morphNormal3;","#else","attribute vec3 morphTarget4;","attribute vec3 morphTarget5;","attribute vec3 morphTarget6;","attribute vec3 morphTarget7;","#endif","#endif","#ifdef USE_SKINNING","attribute vec4 skinIndex;","attribute vec4 skinWeight;","#endif",""].join("\n"),w=["precision "+Ca+" float;","precision "+Ca+" int;",h.bumpMap||h.normalMap?"#extension GL_OES_standard_derivatives : enable":"",t,"#define MAX_DIR_LIGHTS "+h.maxDirLights,"#define MAX_POINT_LIGHTS "+h.maxPointLights,"#define MAX_SPOT_LIGHTS "+h.maxSpotLights,"#define MAX_HEMI_LIGHTS "+h.maxHemiLights,"#define MAX_AREA_LIGHTS "+h.maxAreaLights,"#define MAX_SHADOWS "+h.maxShadows,h.alphaTest?"#define ALPHATEST "+h.alphaTest:"",Ra.gammaInput?"#define GAMMA_INPUT":"",Ra.gammaOutput?"#define GAMMA_OUTPUT":"",h.useFog&&h.fog?"#define USE_FOG":"",h.useFog&&h.fogExp?"#define FOG_EXP2":"",h.map?"#define USE_MAP":"",h.opacityMap?"#define USE_OPACITYMAP":"",h.falloffMap?"#define USE_FALLOFFMAP":"",h.translucencyMap?"#define USE_TRANSLUCENCYMAP":"",h.envMap?"#define USE_ENVMAP":"",h.diffuseEnvMap?"#define USE_DIFFUSEENVMAP":"",h.lightMap?"#define USE_LIGHTMAP":"",h.emissiveMap?"#define USE_EMISSIVEMAP":"",h.bumpMap?"#define USE_BUMPMAP":"",h.reflectivityMap?"#define USE_REFLECTIVITYMAP":"",h.roughnessMap?"#define USE_ROUGHNESSMAP":"",h.metallicMap?"#define USE_METALLICMAP":"",h.normalMap?"#define USE_NORMALMAP":"",h.specularMap?"#define USE_SPECULARMAP":"",h.vertexColors?"#define USE_COLOR":"",h.clearCoat?"#define CLEARCOAT":"",h.translucency?"#define TRANSLUCENCY":"",h.anisotropy?"#define ANISOTROPY":"",h.anisotropyMap?"#define USE_ANISOTROPYMAP":"",h.anisotropy&&h.anisotropyRotation?"#define ANISOTROPYROTATION":"",h.anisotropy&&h.anisotropyRotationMap?"#define USE_ANISOTROPYROTATIONMAP":"",h.falloff?"#define FALLOFF":"",h.wrapAround?"#define WRAP_AROUND":"",h.doubleSided?"#define DOUBLE_SIDED":"",h.flipSided?"#define FLIP_SIDED":"",h.shadowMapEnabled?"#define USE_SHADOWMAP":"",h.shadowMapEnabled?"#define "+s:"",h.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",h.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",u?"#define TEXTURE_CUBE_LOD_EXT":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;",""].join("\n"),x=la("vertex",v+c,a,q),y=la("fragment",w+b,a,q); +Ka.attachShader(m,x,n),Ka.attachShader(m,y,n),void 0!==i&&Ka.bindAttribLocation(m,0,i),Ka.linkProgram(m);var z=Ka.getProgramInfoLog(m);if(Ka.getProgramParameter(m,Ka.LINK_STATUS)===!1){var A=Ka.getError();e.onerror(a+" shader program error: "+A+"\n "+z,{shaderID:a,programInfo:z,glError:A,vertexShader:v+c,fragmentShader:w+b,getProgramParameter_LINK_STATUS:Ka.getProgramParameter(m,Ka.LINK_STATUS),getProgramParameter_VALIDATE_STATUS:Ka.getProgramParameter(m,Ka.VALIDATE_STATUS),getProgramParameter_ATTACHED_SHADERS:Ka.getProgramParameter(m,Ka.ATTACHED_SHADERS),getProgramParameter_ACTIVE_ATTRIBUTES:Ka.getProgramParameter(m,Ka.ACTIVE_ATTRIBUTES),getProgramParameter_ACTIVE_UNIFORMS:Ka.getProgramParameter(m,Ka.ACTIVE_UNIFORMS),gl_MAX_VARYING_VECTORS:Ka.getParameter(Ka.MAX_VARYING_VECTORS),gl_MAX_VERTEX_ATTRIBS:Ka.getParameter(Ka.MAX_VERTEX_ATTRIBS),gl_MAX_VERTEX_UNIFORM_VECTORS:Ka.getParameter(Ka.MAX_VERTEX_UNIFORM_VECTORS),gl_MAX_VERTEX_TEXTURE_IMAGE_UNITS:Ka.getParameter(Ka.MAX_VERTEX_TEXTURE_IMAGE_UNITS),gl_MAX_FRAGMENT_UNIFORM_VECTORS:Ka.getParameter(Ka.MAX_FRAGMENT_UNIFORM_VECTORS),gl_MAX_TEXTURE_IMAGE_UNITS:Ka.getParameter(Ka.MAX_TEXTURE_IMAGE_UNITS)})}Ka.deleteShader(y),Ka.deleteShader(x),m.uniforms={},m.attributes={};var B,C,D,E;B=["viewMatrix","modelViewMatrix","projectionMatrix","normalMatrix","modelMatrix","cameraPosition","morphTargetInfluences"],h.useVertexTexture?(B.push("boneTexture"),B.push("boneTextureWidth"),B.push("boneTextureHeight")):B.push("boneGlobalMatrices");for(C in d)B.push(C);for(ia(m,B),B=["position","normal","uv","uv2","tangent","color","skinIndex","skinWeight","lineDistance"],E=0;Ec;c++)e=b[c],a.uniforms[e]=Ka.getUniformLocation(a,e)}function ja(a,b){var c,d,e;for(c=0,d=b.length;d>c;c++)e=b[c],a.attributes[e]=Ka.getAttribLocation(a,e)}function ka(a){for(var b=a.split("\n"),c=0,d=b.length;d>c;c++)b[c]=c+1+": "+b[c];return b.join("\n")}function la(a,b,c,d){var f;return"fragment"===a?f=Ka.createShader(Ka.FRAGMENT_SHADER):"vertex"===a&&(f=Ka.createShader(Ka.VERTEX_SHADER)),Ka.shaderSource(f,b),Ka.compileShader(f),Ka.getShaderParameter(f,Ka.COMPILE_STATUS)?f:(e.onerror("shader error: "+c+"."+a,{getShaderParameter:Ka.getShaderParameter(f,Ka.COMPILE_STATUS),shaderInfoLog:Ka.getShaderInfoLog(f),shaderCode:ka(b),getError:Ka.getError(),simpleCode:d,gl_MAX_VARYING_VECTORS:Ka.getParameter(Ka.MAX_VARYING_VECTORS),gl_MAX_VERTEX_ATTRIBS:Ka.getParameter(Ka.MAX_VERTEX_ATTRIBS),gl_MAX_VERTEX_UNIFORM_VECTORS:Ka.getParameter(Ka.MAX_VERTEX_UNIFORM_VECTORS),gl_MAX_VERTEX_TEXTURE_IMAGE_UNITS:Ka.getParameter(Ka.MAX_VERTEX_TEXTURE_IMAGE_UNITS),gl_MAX_FRAGMENT_UNIFORM_VECTORS:Ka.getParameter(Ka.MAX_FRAGMENT_UNIFORM_VECTORS),gl_MAX_TEXTURE_IMAGE_UNITS:Ka.getParameter(Ka.MAX_TEXTURE_IMAGE_UNITS)}),null)}function ma(a,b,c){c?(Ka.texParameteri(a,Ka.TEXTURE_WRAP_S,ua(b.wrapS)),Ka.texParameteri(a,Ka.TEXTURE_WRAP_T,ua(b.wrapT)),Ka.texParameteri(a,Ka.TEXTURE_MAG_FILTER,ua(b.magFilter)),Ka.texParameteri(a,Ka.TEXTURE_MIN_FILTER,ua(b.minFilter))):(Ka.texParameteri(a,Ka.TEXTURE_WRAP_S,Ka.CLAMP_TO_EDGE),Ka.texParameteri(a,Ka.TEXTURE_WRAP_T,Ka.CLAMP_TO_EDGE),Ka.texParameteri(a,Ka.TEXTURE_MAG_FILTER,ta(b.magFilter)),Ka.texParameteri(a,Ka.TEXTURE_MIN_FILTER,ta(b.minFilter))),Pa&&b.type!==e.FloatType&&(b.anisotropy>1||b.__oldAnisotropy)&&(Ka.texParameterf(a,Pa.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(b.anisotropy,Db)),b.__oldAnisotropy=b.anisotropy)}function na(a,b){if(a.width<=b&&a.height<=b)return a;var c=Math.max(a.width,a.height),d=Math.floor(a.width*b/c),e=Math.floor(a.height*b/c),f=document.createElement("canvas");f.width=d,f.height=e;var g=f.getContext("2d");return g.drawImage(a,0,0,a.width,a.height,0,0,d,e),f}function oa(a,b){if(6===a.image.length)if(a.needsUpdate){a.image.__webglTextureCube||(a.addEventListener("dispose",Nb),a.image.__webglTextureCube=Ka.createTexture(),Ra.info.memory.textures++),Ka.activeTexture(Ka.TEXTURE0+b),Ka.bindTexture(Ka.TEXTURE_CUBE_MAP,a.image.__webglTextureCube),Ka.pixelStorei(Ka.UNPACK_FLIP_Y_WEBGL,a.flipY);for(var c=a instanceof e.CompressedTexture,d=[],f=0;6>f;f++)Ra.autoScaleCubemaps&&!c?d[f]=na(a.image[f],Cb):d[f]=a.image[f];var g=d[0],h=e.Math.isPowerOfTwo(g.width)&&e.Math.isPowerOfTwo(g.height),i=ua(a.format),j=ua(a.type);ma(Ka.TEXTURE_CUBE_MAP,a,h);for(var f=0;6>f;f++)if(c)for(var k,l=d[f].mipmaps,m=0,n=l.length;n>m;m++)k=l[m],a.format!==e.RGBAFormat?(Ka.compressedTexImage2D(Ka.TEXTURE_CUBE_MAP_POSITIVE_X+f,m,i,k.width,k.height,0,k.data),Vb("_gl.compressedTexImage2D CubeMap Mipmaps Compressed, texture.name: "+a.name,a)):(Ka.texImage2D(Ka.TEXTURE_CUBE_MAP_POSITIVE_X+f,m,i,k.width,k.height,0,i,j,k.data),Vb("_gl.texImage2D CubeMap Mipmaps Compressed RGBA, texture.name: "+a.name,a));else Ka.texImage2D(Ka.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,i,i,j,d[f]),Vb("_gl.texImage2D CubeMap, texture.name: "+a.name,{texture:a,cubeImage:d,index:f});a.generateMipmaps&&h&&(Ka.generateMipmap(Ka.TEXTURE_CUBE_MAP),Vb("_gl.generateMipmap CubeMap Mipmaps, texture.name: "+a.name,a)),a.needsUpdate=!1,a.onUpdate&&a.onUpdate()}else Ka.activeTexture(Ka.TEXTURE0+b),Ka.bindTexture(Ka.TEXTURE_CUBE_MAP,a.image.__webglTextureCube)}function pa(a,b){Ka.activeTexture(Ka.TEXTURE0+b),Ka.bindTexture(Ka.TEXTURE_CUBE_MAP,a.__webglTexture)}function qa(a,b,c){Ka.bindFramebuffer(Ka.FRAMEBUFFER,a),Ka.framebufferTexture2D(Ka.FRAMEBUFFER,Ka.COLOR_ATTACHMENT0,c,b.__webglTexture,0)}function ra(a,b){Ka.bindRenderbuffer(Ka.RENDERBUFFER,a);var c="";if(b.depthBuffer&&!b.stencilBuffer?(Ka.renderbufferStorage(Ka.RENDERBUFFER,Ka.DEPTH_COMPONENT16,b.width,b.height),Ka.framebufferRenderbuffer(Ka.FRAMEBUFFER,Ka.DEPTH_ATTACHMENT,Ka.RENDERBUFFER,a),c="renderTarget: "+b.width+"+"+b.height+" DEPTH_ATTACHMENT"):b.depthBuffer&&b.stencilBuffer?(Ka.renderbufferStorage(Ka.RENDERBUFFER,Ka.DEPTH_STENCIL,b.width,b.height),Ka.framebufferRenderbuffer(Ka.FRAMEBUFFER,Ka.DEPTH_STENCIL_ATTACHMENT,Ka.RENDERBUFFER,a),c="renderTarget: "+b.width+"+"+b.height+" DEPTH_STENCIL_ATTACHMENT"):(Ka.renderbufferStorage(Ka.RENDERBUFFER,Ka.RGBA4,b.width,b.height),c="renderTarget: "+b.width+"+"+b.height+" RGBA4"),Ka.checkFramebufferStatus(Ka.FRAMEBUFFER)!=Ka.FRAMEBUFFER_COMPLETE)throw console.log(b),new Error("(A) Rendering to this texture (renderTarget.name: "+b.name+") is not supported (incomplete framebuffer) "+c)}function sa(a){a instanceof e.WebGLRenderTargetCube?(Ka.bindTexture(Ka.TEXTURE_CUBE_MAP,a.__webglTexture),Ka.generateMipmap(Ka.TEXTURE_CUBE_MAP),Vb("_gl.generateMipmap CubeMap, renderTarget.name: "+a.name,a),Ka.bindTexture(Ka.TEXTURE_CUBE_MAP,null)):(Ka.bindTexture(Ka.TEXTURE_2D,a.__webglTexture),Ka.generateMipmap(Ka.TEXTURE_2D),Vb("_gl.generateMipmap, renderTarget.name: "+a.name,a),Ka.bindTexture(Ka.TEXTURE_2D,null))}function ta(a){return a===e.NearestFilter||a===e.NearestMipMapNearestFilter||a===e.NearestMipMapLinearFilter?Ka.NEAREST:Ka.LINEAR}function ua(a){if(a===e.RepeatWrapping)return Ka.REPEAT;if(a===e.ClampToEdgeWrapping)return Ka.CLAMP_TO_EDGE;if(a===e.MirroredRepeatWrapping)return Ka.MIRRORED_REPEAT;if(a===e.NearestFilter)return Ka.NEAREST;if(a===e.NearestMipMapNearestFilter)return Ka.NEAREST_MIPMAP_NEAREST;if(a===e.NearestMipMapLinearFilter)return Ka.NEAREST_MIPMAP_LINEAR;if(a===e.LinearFilter)return Ka.LINEAR;if(a===e.LinearMipMapNearestFilter)return Ka.LINEAR_MIPMAP_NEAREST;if(a===e.LinearMipMapLinearFilter)return Ka.LINEAR_MIPMAP_LINEAR;if(a===e.UnsignedByteType)return Ka.UNSIGNED_BYTE;if(a===e.UnsignedShort4444Type)return Ka.UNSIGNED_SHORT_4_4_4_4;if(a===e.UnsignedShort5551Type)return Ka.UNSIGNED_SHORT_5_5_5_1;if(a===e.UnsignedShort565Type)return Ka.UNSIGNED_SHORT_5_6_5;if(a===e.ByteType)return Ka.BYTE;if(a===e.ShortType)return Ka.SHORT;if(a===e.UnsignedShortType)return Ka.UNSIGNED_SHORT;if(a===e.IntType)return Ka.INT;if(a===e.UnsignedIntType)return Ka.UNSIGNED_INT;if(a===e.FloatType)return Ka.FLOAT;if(a===e.HalfType)return 36193;if(a===e.AlphaFormat)return Ka.ALPHA;if(a===e.RGBFormat)return Ka.RGB;if(a===e.RGBAFormat)return Ka.RGBA;if(a===e.LuminanceFormat)return Ka.LUMINANCE;if(a===e.LuminanceAlphaFormat)return Ka.LUMINANCE_ALPHA;if(a===e.AddEquation)return Ka.FUNC_ADD;if(a===e.SubtractEquation)return Ka.FUNC_SUBTRACT;if(a===e.ReverseSubtractEquation)return Ka.FUNC_REVERSE_SUBTRACT;if(a===e.ZeroFactor)return Ka.ZERO;if(a===e.OneFactor)return Ka.ONE;if(a===e.SrcColorFactor)return Ka.SRC_COLOR;if(a===e.OneMinusSrcColorFactor)return Ka.ONE_MINUS_SRC_COLOR;if(a===e.SrcAlphaFactor)return Ka.SRC_ALPHA;if(a===e.OneMinusSrcAlphaFactor)return Ka.ONE_MINUS_SRC_ALPHA;if(a===e.DstAlphaFactor)return Ka.DST_ALPHA;if(a===e.OneMinusDstAlphaFactor)return Ka.ONE_MINUS_DST_ALPHA;if(a===e.DstColorFactor)return Ka.DST_COLOR;if(a===e.OneMinusDstColorFactor)return Ka.ONE_MINUS_DST_COLOR;if(a===e.SrcAlphaSaturateFactor)return Ka.SRC_ALPHA_SATURATE;if(void 0!==Qa){if(a===e.RGB_S3TC_DXT1_Format)return Qa.COMPRESSED_RGB_S3TC_DXT1_EXT;if(a===e.RGBA_S3TC_DXT1_Format)return Qa.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(a===e.RGBA_S3TC_DXT3_Format)return Qa.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(a===e.RGBA_S3TC_DXT5_Format)return Qa.COMPRESSED_RGBA_S3TC_DXT5_EXT}return 0}function va(a){if(Fb&&a&&a.useVertexTexture)return 1024;var b=Ka.getParameter(Ka.MAX_VERTEX_UNIFORM_VECTORS),c=Math.floor((b-20)/4),d=c;return void 0!==a&&a instanceof e.SkinnedMesh&&(d=Math.min(a.bones.length,d),dh;h++){var j=a[h];j.onlyShadow||j.visible===!1||(j instanceof e.DirectionalLight&&b++,j instanceof e.PointLight&&c++,j instanceof e.SpotLight&&d++,j instanceof e.HemisphereLight&&f++,j instanceof e.AreaLight&&g++)}return{directional:b,point:c,spot:d,hemi:f,area:g}}function xa(a){for(var b=0,c=0,d=a.length;d>c;c++){var f=a[c];f.castShadow&&(f instanceof e.SpotLight&&b++,f instanceof e.DirectionalLight&&!f.shadowCascade&&b++)}return b}function ya(){try{var a={alpha:Da,premultipliedAlpha:Ea,antialias:Fa,stencil:Ga,preserveDrawingBuffer:Ha};Ka=Ba||Aa.getContext("webgl",a)||Aa.getContext("experimental-webgl",a),null===Ka&&e.onerror("Error creating WebGL context.")}catch(b){e.onerror(b)}La=Ka.getExtension("OES_texture_float"),Ma=Ka.getExtension("OES_texture_float_linear"),Na=Ka.getExtension("OES_standard_derivatives"),Oa=Ka.getExtension("EXT_shader_texture_lod"),Pa=Ka.getExtension("EXT_texture_filter_anisotropic")||Ka.getExtension("MOZ_EXT_texture_filter_anisotropic")||Ka.getExtension("WEBKIT_EXT_texture_filter_anisotropic"),Qa=Ka.getExtension("WEBGL_compressed_texture_s3tc")||Ka.getExtension("MOZ_WEBGL_compressed_texture_s3tc")||Ka.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc"),La||console.log("THREE.WebGLRenderer: Float textures not supported."),Na||console.log("THREE.WebGLRenderer: Standard derivatives not supported."),Oa||console.log("THREE.WebGLRenderer: Shader texture LOD not supported."),Pa||console.log("THREE.WebGLRenderer: Anisotropic texture filtering not supported."),Qa||console.log("THREE.WebGLRenderer: S3TC compressed textures not supported."),void 0===Ka.getShaderPrecisionFormat&&(Ka.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}})}function za(){Ka.clearColor(0,0,0,1),Ka.clearDepth(1),Ka.clearStencil(0),Ka.enable(Ka.DEPTH_TEST),Ka.depthFunc(Ka.LEQUAL),Ka.frontFace(Ka.CCW),Ka.cullFace(Ka.BACK),Ka.enable(Ka.CULL_FACE),Ka.enable(Ka.BLEND),Ka.blendEquation(Ka.FUNC_ADD),Ka.blendFunc(Ka.SRC_ALPHA,Ka.ONE_MINUS_SRC_ALPHA),Ka.viewport(kb,lb,mb,nb),Ka.clearColor(Ia.r,Ia.g,Ia.b,Ja)}console.log("THREE.WebGLRenderer",e.REVISION),a=a||{};var Aa=void 0!==a.canvas?a.canvas:document.createElement("canvas"),Ba=void 0!==a.context?a.context:null,Ca=void 0!==a.precision?a.precision:"mediump",Da=void 0!==a.alpha?a.alpha:!1,Ea=void 0!==a.premultipliedAlpha?a.premultipliedAlpha:!0,Fa=void 0!==a.antialias?a.antialias:!1,Ga=void 0!==a.stencil?a.stencil:!0,Ha=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,Ia=new e.Color(0),Ja=0;this.domElement=Aa,this.context=null,this.devicePixelRatio=void 0!==a.devicePixelRatio?a.devicePixelRatio:void 0!==d.devicePixelRatio?d.devicePixelRatio:1,this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.autoUpdateObjects=!0,this.gammaInput=!0,this.gammaOutput=!0,this.shadowMapEnabled=!1,this.shadowMapAutoUpdate=!0,this.shadowMapType=e.PCFShadowMap,this.shadowMapCullFace=e.CullFaceFront,this.shadowMapDebug=!1,this.shadowMapCascade=!1,this.maxMorphTargets=8,this.maxMorphNormals=4,this.autoScaleCubemaps=!0,this.renderPluginsPre=[],this.renderPluginsPost=[],this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}};var Ka,La,Ma,Na,Oa,Pa,Qa,Ra=this,Sa=[],Ta=0,Ua=null,Va=null,Wa=-1,Xa=null,Ya=null,Za=0,$a=-1,_a=-1,ab=-1,bb=-1,cb=-1,db=-1,eb=-1,fb=-1,gb=null,hb=null,ib=null,jb=null,kb=0,lb=0,mb=Aa.width,nb=Aa.height,ob=0,pb=0,qb=new Uint8Array(16),rb=new e.Frustum,sb=new e.Matrix4,tb=new e.Matrix4,ub=new e.Vector3,vb=new e.Vector3,wb=new e.Vector3,xb=new e.Vector3,yb=!0,zb={ambient:[0,0,0],directional:{length:0,colors:new Array,positions:new Array},point:{length:0,colors:new Array,positions:new Array,distances:new Array,decayExponents:new Array},spot:{length:0,colors:new Array,positions:new Array,distances:new Array,decayExponents:new Array,directions:new Array,anglesCos:new Array,exponents:new Array},hemi:{length:0,skyColors:new Array,groundColors:new Array,positions:new Array},area:{length:0,colors:new Array,positions:new Array,distances:new Array,decayExponents:new Array,widths:new Array,heights:new Array}};ya(),za(),this.context=Ka;var Ab=Ka.getParameter(Ka.MAX_TEXTURE_IMAGE_UNITS),Bb=Ka.getParameter(Ka.MAX_VERTEX_TEXTURE_IMAGE_UNITS),Cb=(Ka.getParameter(Ka.MAX_TEXTURE_SIZE),Ka.getParameter(Ka.MAX_CUBE_MAP_TEXTURE_SIZE)),Db=Pa?Ka.getParameter(Pa.MAX_TEXTURE_MAX_ANISOTROPY_EXT):0,Eb=Bb>0,Fb=Eb&&La,Gb=(Qa?Ka.getParameter(Ka.COMPRESSED_TEXTURE_FORMATS):[],Ka.getShaderPrecisionFormat(Ka.VERTEX_SHADER,Ka.HIGH_FLOAT)),Hb=Ka.getShaderPrecisionFormat(Ka.VERTEX_SHADER,Ka.MEDIUM_FLOAT),Ib=(Ka.getShaderPrecisionFormat(Ka.VERTEX_SHADER,Ka.LOW_FLOAT),Ka.getShaderPrecisionFormat(Ka.FRAGMENT_SHADER,Ka.HIGH_FLOAT)),Jb=Ka.getShaderPrecisionFormat(Ka.FRAGMENT_SHADER,Ka.MEDIUM_FLOAT),Kb=(Ka.getShaderPrecisionFormat(Ka.FRAGMENT_SHADER,Ka.LOW_FLOAT),Ka.getShaderPrecisionFormat(Ka.VERTEX_SHADER,Ka.HIGH_INT),Ka.getShaderPrecisionFormat(Ka.VERTEX_SHADER,Ka.MEDIUM_INT),Ka.getShaderPrecisionFormat(Ka.VERTEX_SHADER,Ka.LOW_INT),Ka.getShaderPrecisionFormat(Ka.FRAGMENT_SHADER,Ka.HIGH_INT),Ka.getShaderPrecisionFormat(Ka.FRAGMENT_SHADER,Ka.MEDIUM_INT),Ka.getShaderPrecisionFormat(Ka.FRAGMENT_SHADER,Ka.LOW_INT),Gb.precision>0&&Ib.precision>0),Lb=Hb.precision>0&&Jb.precision>0;"highp"!==Ca||Kb||(Lb?(Ca="mediump",e.onwarning("WebGLRenderer: highp not supported, using mediump")):(Ca="lowp",e.onwarning("WebGLRenderer: highp and mediump not supported, using lowp"))),"mediump"!==Ca||Lb||(Ca="lowp",e.onwarning("WebGLRenderer: mediump not supported, using lowp")),this.getContext=function(){return Ka},this.supportsVertexTextures=function(){return Eb},this.supportsFloatTextures=function(){return La},this.supportsStandardDerivatives=function(){return Na},this.supportsCompressedTextureS3TC=function(){return Qa},this.getMaxAnisotropy=function(){return Db},this.getPrecision=function(){return Ca},this.setSize=function(a,b,c){Aa.width=a*this.devicePixelRatio,Aa.height=b*this.devicePixelRatio,1!==this.devicePixelRatio&&c!==!1&&(Aa.style.width=a+"px",Aa.style.height=b+"px"),this.setViewport(0,0,a,b)},this.setViewport=function(a,b,c,d){kb=a*this.devicePixelRatio,lb=b*this.devicePixelRatio,mb=c*this.devicePixelRatio,nb=d*this.devicePixelRatio,Ka.viewport(kb,lb,mb,nb)},this.setScissor=function(a,b,c,d){Ka.scissor(a*this.devicePixelRatio,b*this.devicePixelRatio,c*this.devicePixelRatio,d*this.devicePixelRatio)},this.enableScissorTest=function(a){a?Ka.enable(Ka.SCISSOR_TEST):Ka.disable(Ka.SCISSOR_TEST)},this.setClearColor=function(a,b){Ia.set(a),Ja=void 0!==b?b:1,Ka.clearColor(Ia.r,Ia.g,Ia.b,Ja)},this.setClearColorHex=function(a,b){e.onwarning("DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead."),this.setClearColor(a,b)},this.getClearColor=function(){return Ia},this.getClearAlpha=function(){return Ja},this.clear=function(a,b,c){var d=0;(void 0===a||a)&&(d|=Ka.COLOR_BUFFER_BIT),(void 0===b||b)&&(d|=Ka.DEPTH_BUFFER_BIT),(void 0===c||c)&&(d|=Ka.STENCIL_BUFFER_BIT),Ka.clear(d)},this.clearColor=function(){Ka.clear(Ka.COLOR_BUFFER_BIT)},this.clearDepth=function(){Ka.clear(Ka.DEPTH_BUFFER_BIT)},this.clearStencil=function(){Ka.clear(Ka.STENCIL_BUFFER_BIT)},this.clearTarget=function(a,b,c,d){this.setRenderTarget(a),this.clear(b,c,d)},this.addPostPlugin=function(a){a.init(this),this.renderPluginsPost.push(a)},this.addPrePlugin=function(a){a.init(this),this.renderPluginsPre.push(a)},this.updateShadowMap=function(a,b){Ua=null,ab=-1,eb=-1,fb=-1,Xa=-1,Wa=-1,yb=!0,$a=-1,_a=-1,this.shadowMapPlugin.update(a,b)};var Mb=function(a){var b=a.target;b.removeEventListener("dispose",Mb),Rb(b)},Nb=function(a){var b=a.target;b.removeEventListener("dispose",Nb),Sb(b),Ra.info.memory.textures--},Ob=function(a){var b=a.target;b.removeEventListener("dispose",Ob),Tb(b),Ra.info.memory.textures--},Pb=function(a){var b=a.target;b.removeEventListener("dispose",Pb),Ub(b)},Qb=function(a){if(void 0!==a.__webglVertexBuffer&&Ka.deleteBuffer(a.__webglVertexBuffer),void 0!==a.__webglNormalBuffer&&Ka.deleteBuffer(a.__webglNormalBuffer),void 0!==a.__webglTangentBuffer&&Ka.deleteBuffer(a.__webglTangentBuffer),void 0!==a.__webglColorBuffer&&Ka.deleteBuffer(a.__webglColorBuffer),void 0!==a.__webglUVBuffer&&Ka.deleteBuffer(a.__webglUVBuffer),void 0!==a.__webglUV2Buffer&&Ka.deleteBuffer(a.__webglUV2Buffer),void 0!==a.__webglSkinIndicesBuffer&&Ka.deleteBuffer(a.__webglSkinIndicesBuffer),void 0!==a.__webglSkinWeightsBuffer&&Ka.deleteBuffer(a.__webglSkinWeightsBuffer),void 0!==a.__webglFaceBuffer&&Ka.deleteBuffer(a.__webglFaceBuffer),void 0!==a.__webglLineBuffer&&Ka.deleteBuffer(a.__webglLineBuffer),void 0!==a.__webglLineDistanceBuffer&&Ka.deleteBuffer(a.__webglLineDistanceBuffer),void 0!==a.__webglCustomAttributesList)for(var b in a.__webglCustomAttributesList)Ka.deleteBuffer(a.__webglCustomAttributesList[b].buffer);Ra.info.memory.geometries--},Rb=function(a){if(a.__webglInit=void 0,a instanceof e.BufferGeometry){var b=a.attributes;for(var c in b)void 0!==b[c].buffer&&Ka.deleteBuffer(b[c].buffer);Ra.info.memory.geometries--}else if(void 0!==a.geometryGroups)for(var d in a.geometryGroups){var f=a.geometryGroups[d];if(void 0!==f.numMorphTargets)for(var g=0,h=f.numMorphTargets;h>g;g++)Ka.deleteBuffer(f.__webglMorphTargetsBuffers[g]);if(void 0!==f.numMorphNormals)for(var g=0,h=f.numMorphNormals;h>g;g++)Ka.deleteBuffer(f.__webglMorphNormalsBuffers[g]);Qb(f)}else Qb(a)},Sb=function(a){if(a.image&&a.image.__webglTextureCube)Ka.deleteTexture(a.image.__webglTextureCube);else{if(!a.__webglInit)return;a.__webglInit=!1,Ka.deleteTexture(a.__webglTexture)}},Tb=function(a){if(a&&a.__webglTexture)if(Ka.deleteTexture(a.__webglTexture),a instanceof e.WebGLRenderTargetCube)for(var b=0;6>b;b++)Ka.deleteFramebuffer(a.__webglFramebuffer[b]),Ka.deleteRenderbuffer(a.__webglRenderbuffer[b]);else Ka.deleteFramebuffer(a.__webglFramebuffer),Ka.deleteRenderbuffer(a.__webglRenderbuffer)},Ub=function(a,b){var c=b||a.program;if(void 0!==c){b||(a.program=void 0);var d,e,f,g=!1;for(d=0,e=Sa.length;e>d;d++)if(f=Sa[d],f.program===c){f.usedTimes--,0===f.usedTimes&&(g=!0);break}if(g===!0){var h=[];for(d=0,e=Sa.length;e>d;d++)f=Sa[d],f.program!==c&&h.push(f);Sa=h,Ka.deleteProgram(c),Ra.info.memory.programs--}}};this.renderBufferImmediate=function(a,b,c){if(a.hasPositions&&!a.__webglVertexBuffer&&(a.__webglVertexBuffer=Ka.createBuffer()),a.hasNormals&&!a.__webglNormalBuffer&&(a.__webglNormalBuffer=Ka.createBuffer()),a.hasUvs&&!a.__webglUvBuffer&&(a.__webglUvBuffer=Ka.createBuffer()),a.hasColors&&!a.__webglColorBuffer&&(a.__webglColorBuffer=Ka.createBuffer()),a.hasPositions&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglVertexBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,a.positionArray,Ka.DYNAMIC_DRAW),Ka.enableVertexAttribArray(b.attributes.position),Ka.vertexAttribPointer(b.attributes.position,3,Ka.FLOAT,!1,0,0)),a.hasNormals){if(Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglNormalBuffer),c.shading===e.FlatShading){var d,f,g,h,i,j,k,l,m,n,o,p,q,r,s=3*a.count;for(r=0;s>r;r+=9)q=a.normalArray,h=q[r],k=q[r+1],n=q[r+2],i=q[r+3],l=q[r+4],o=q[r+5],j=q[r+6],m=q[r+7],p=q[r+8],d=(h+i+j)/3,f=(k+l+m)/3,g=(n+o+p)/3,q[r]=d,q[r+1]=f,q[r+2]=g,q[r+3]=d,q[r+4]=f,q[r+5]=g,q[r+6]=d,q[r+7]=f,q[r+8]=g}Ka.bufferData(Ka.ARRAY_BUFFER,a.normalArray,Ka.DYNAMIC_DRAW),Ka.enableVertexAttribArray(b.attributes.normal),Ka.vertexAttribPointer(b.attributes.normal,3,Ka.FLOAT,!1,0,0)}a.hasUvs&&c.map&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglUvBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,a.uvArray,Ka.DYNAMIC_DRAW),Ka.enableVertexAttribArray(b.attributes.uv),Ka.vertexAttribPointer(b.attributes.uv,2,Ka.FLOAT,!1,0,0)),a.hasColors&&c.vertexColors!==e.NoColors&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,a.__webglColorBuffer),Ka.bufferData(Ka.ARRAY_BUFFER,a.colorArray,Ka.DYNAMIC_DRAW),Ka.enableVertexAttribArray(b.attributes.color),Ka.vertexAttribPointer(b.attributes.color,3,Ka.FLOAT,!1,0,0)),Ka.drawArrays(Ka.TRIANGLES,0,a.count),a.count=0},this.renderBufferDirect=function(a,b,c,d,f,g){if(d.visible!==!1){var h,i,j,k,l=P(a,b,c,d,g),m=l.attributes,n=f.attributes,o=!1,p=d.wireframe?1:0,q=16777215*f.id+2*l.id+p;if(q!==Xa&&(Xa=q,o=!0),o&&w(),g instanceof e.Mesh){var r=n.index;if(r){var s=f.offsets;s.length>1&&(o=!0);for(var u=0,x=s.length;x>u;u++){var y=s[u].index;if(o){for(i in m)j=m[i],h=n[i],j>=0&&(h?(k=h.itemSize,Ka.bindBuffer(Ka.ARRAY_BUFFER,h.buffer),v(j),Ka.vertexAttribPointer(j,k,Ka.FLOAT,!1,0,y*k*4)):d.defaultAttributeValues&&(2===d.defaultAttributeValues[i].length?Ka.vertexAttrib2fv(j,d.defaultAttributeValues[i]):3===d.defaultAttributeValues[i].length&&Ka.vertexAttrib3fv(j,d.defaultAttributeValues[i])));Ka.bindBuffer(Ka.ELEMENT_ARRAY_BUFFER,r.buffer)}Ka.drawElements(Ka.TRIANGLES,s[u].count,Ka.UNSIGNED_SHORT,2*s[u].start),Ra.info.render.calls++,Ra.info.render.vertices+=s[u].count,Ra.info.render.faces+=s[u].count/3}}else{if(o)for(i in m)"index"!==i&&(j=m[i],h=n[i],j>=0&&(h?(k=h.itemSize,Ka.bindBuffer(Ka.ARRAY_BUFFER,h.buffer),v(j),Ka.vertexAttribPointer(j,k,Ka.FLOAT,!1,0,0)):d.defaultAttributeValues&&d.defaultAttributeValues[i]&&(2===d.defaultAttributeValues[i].length?Ka.vertexAttrib2fv(j,d.defaultAttributeValues[i]):3===d.defaultAttributeValues[i].length&&Ka.vertexAttrib3fv(j,d.defaultAttributeValues[i]))));var z=f.attributes.position;Ka.drawArrays(Ka.TRIANGLES,0,z.array.length/3),Ra.info.render.calls++,Ra.info.render.vertices+=z.array.length/3,Ra.info.render.faces+=z.array.length/3/3}}else if(g instanceof e.ParticleSystem){if(o)for(i in m)j=m[i],h=n[i],j>=0&&(h?(k=h.itemSize,Ka.bindBuffer(Ka.ARRAY_BUFFER,h.buffer),v(j),Ka.vertexAttribPointer(j,k,Ka.FLOAT,!1,0,0)):d.defaultAttributeValues&&d.defaultAttributeValues[i]&&(2===d.defaultAttributeValues[i].length?Ka.vertexAttrib2fv(j,d.defaultAttributeValues[i]):3===d.defaultAttributeValues[i].length&&Ka.vertexAttrib3fv(j,d.defaultAttributeValues[i])));var z=n.position;Ka.drawArrays(Ka.POINTS,0,z.array.length/3),Ra.info.render.calls++,Ra.info.render.points+=z.array.length/3}else if(g instanceof e.Line){var A=g.type===e.LineStrip?Ka.LINE_STRIP:Ka.LINES;ea(d.linewidth);var r=n.index;if(r){var s=f.offsets;s.length>1&&(o=!0);for(var u=0,x=s.length;x>u;u++){var y=s[u].index;o&&(t(d,m,n,y),Ka.bindBuffer(Ka.ELEMENT_ARRAY_BUFFER,r.buffer)),Ka.drawElements(Ka.LINES,s[u].count,Ka.UNSIGNED_SHORT,2*s[u].start),Ra.info.render.calls++,Ra.info.render.vertices+=s[u].count}}else{o&&t(d,m,n,0);var z=n.position;Ka.drawArrays(A,0,z.array.length/3),Ra.info.render.calls++,Ra.info.render.points+=z.array.length}}}},this.renderBuffer=function(a,b,c,d,f,g){if(d.visible!==!1){var h,i,j,k=P(a,b,c,d,g),l=k.attributes,m=!1,n=d.wireframe?1:0,o=16777215*f.id+2*k.id+n;if(o!==Xa&&(Xa=o,m=!0),m&&w(),!d.morphTargets&&l.position>=0?m&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,f.__webglVertexBuffer),v(l.position),Ka.vertexAttribPointer(l.position,3,Ka.FLOAT,!1,0,0)):g.morphTargetBase&&x(d,f,g),m){if(f.__webglCustomAttributesList)for(i=0,j=f.__webglCustomAttributesList.length;j>i;i++)h=f.__webglCustomAttributesList[i],l[h.buffer.belongsToAttribute]>=0&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,h.buffer),v(l[h.buffer.belongsToAttribute]),Ka.vertexAttribPointer(l[h.buffer.belongsToAttribute],h.size,Ka.FLOAT,!1,0,0));l.color>=0&&(g.geometry.colors.length>0||g.geometry.faces.length>0?(Ka.bindBuffer(Ka.ARRAY_BUFFER,f.__webglColorBuffer),v(l.color),Ka.vertexAttribPointer(l.color,3,Ka.FLOAT,!1,0,0)):d.defaultAttributeValues&&Ka.vertexAttrib3fv(l.color,d.defaultAttributeValues.color)),l.normal>=0&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,f.__webglNormalBuffer),v(l.normal),Ka.vertexAttribPointer(l.normal,3,Ka.FLOAT,!1,0,0)),l.tangent>=0&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,f.__webglTangentBuffer),v(l.tangent),Ka.vertexAttribPointer(l.tangent,4,Ka.FLOAT,!1,0,0)),l.uv>=0&&(g.geometry.faceVertexUvs[0]?(Ka.bindBuffer(Ka.ARRAY_BUFFER,f.__webglUVBuffer),v(l.uv),Ka.vertexAttribPointer(l.uv,2,Ka.FLOAT,!1,0,0)):d.defaultAttributeValues&&Ka.vertexAttrib2fv(l.uv,d.defaultAttributeValues.uv)),l.uv2>=0&&(g.geometry.faceVertexUvs[1]?(Ka.bindBuffer(Ka.ARRAY_BUFFER,f.__webglUV2Buffer),v(l.uv2),Ka.vertexAttribPointer(l.uv2,2,Ka.FLOAT,!1,0,0)):d.defaultAttributeValues&&Ka.vertexAttrib2fv(l.uv2,d.defaultAttributeValues.uv2)),d.skinning&&l.skinIndex>=0&&l.skinWeight>=0&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,f.__webglSkinIndicesBuffer),v(l.skinIndex),Ka.vertexAttribPointer(l.skinIndex,4,Ka.FLOAT,!1,0,0),Ka.bindBuffer(Ka.ARRAY_BUFFER,f.__webglSkinWeightsBuffer),v(l.skinWeight),Ka.vertexAttribPointer(l.skinWeight,4,Ka.FLOAT,!1,0,0)),l.lineDistance>=0&&(Ka.bindBuffer(Ka.ARRAY_BUFFER,f.__webglLineDistanceBuffer),v(l.lineDistance),Ka.vertexAttribPointer(l.lineDistance,1,Ka.FLOAT,!1,0,0))}if(g instanceof e.Mesh)d.wireframe?(ea(d.wireframeLinewidth),m&&Ka.bindBuffer(Ka.ELEMENT_ARRAY_BUFFER,f.__webglLineBuffer),Ka.drawElements(Ka.LINES,f.__webglLineCount,Ka.UNSIGNED_SHORT,0)):(m&&Ka.bindBuffer(Ka.ELEMENT_ARRAY_BUFFER,f.__webglFaceBuffer),Ka.drawElements(Ka.TRIANGLES,f.__webglFaceCount,Ka.UNSIGNED_SHORT,0)),Ra.info.render.calls++,Ra.info.render.vertices+=f.__webglFaceCount,Ra.info.render.faces+=f.__webglFaceCount/3;else if(g instanceof e.Line){var p=g.type===e.LineStrip?Ka.LINE_STRIP:Ka.LINES;ea(d.linewidth),Ka.drawArrays(p,0,f.__webglLineCount),Ra.info.render.calls++}else g instanceof e.ParticleSystem&&(Ka.drawArrays(Ka.POINTS,0,f.__webglParticleCount),Ra.info.render.calls++,Ra.info.render.points+=f.__webglParticleCount)}},this.render=function(a,b,c,d){if(b instanceof e.Camera==!1)return void e.onerror("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");var f,g,h,i,j,k=a.__lights,l=a.fog;for(Wa=-1,yb=!0,a.autoUpdate===!0&&a.updateMatrixWorld(),void 0===b.parent&&b.updateMatrixWorld(),b.matrixWorldInverse.getInverse(b.matrixWorld),sb.multiplyMatrices(b.projectionMatrix,b.matrixWorldInverse),rb.setFromMatrix(sb),this.autoUpdateObjects&&this.initWebGLObjects(a),A(this.renderPluginsPre,a,b),Ra.info.render.calls=0,Ra.info.render.vertices=0,Ra.info.render.faces=0,Ra.info.render.points=0,this.setRenderTarget(c),(this.autoClear||d)&&this.clear(this.autoClearColor,this.autoClearDepth,this.autoClearStencil),j=a.__webglObjects,f=0,g=j.length;g>f;f++)h=j[f],i=h.object,h.id=f,h.render=!1,i.visible&&((i instanceof e.Mesh||i instanceof e.ParticleSystem)&&i.frustumCulled&&!rb.intersectsObject(i)||(ba(i,b),E(h),h.render=!0,this.sortObjects===!0&&(null!==i.renderDepth?h.z=i.renderDepth:(ub.setFromMatrixPosition(i.matrixWorld),ub.applyProjection(sb),h.z=ub.z))));for(this.sortObjects&&j.sort(y),j=a.__webglObjectsImmediate,f=0,g=j.length;g>f;f++)h=j[f],i=h.object,i.visible&&(ba(i,b),D(h));if(a.overrideMaterial){var m=a.overrideMaterial;this.setBlending(m.blending,m.blendEquation,m.blendSrc,m.blendDst),this.setDepthTest(m.depthTest),this.setDepthWrite(m.depthWrite),fa(m.polygonOffset,m.polygonOffsetFactor,m.polygonOffsetUnits),B(a.__webglObjects,!1,"",b,k,l,!0,m),C(a.__webglObjectsImmediate,"",b,k,l,!1,m)}else{var m=null;this.setBlending(e.NoBlending),B(a.__webglObjects,!0,"opaque",b,k,l,!1,m),C(a.__webglObjectsImmediate,"opaque",b,k,l,!1,m),B(a.__webglObjects,!1,"transparent",b,k,l,!0,m),C(a.__webglObjectsImmediate,"transparent",b,k,l,!0,m)}A(this.renderPluginsPost,a,b),c&&c.generateMipmaps&&c.minFilter!==e.NearestFilter&&c.minFilter!==e.LinearFilter&&e.isPowerOfTwo(c.width)&&e.isPowerOfTwo(c.height)&&sa(c),this.setDepthTest(!0),this.setDepthWrite(!0)},this.renderImmediateObject=function(a,b,c,d,e){var f=P(a,b,c,d,e);Xa=-1,Ra.setMaterialFaces(d),e.immediateRenderCallback?e.immediateRenderCallback(f,Ka,rb):e.render(function(a){Ra.renderBufferImmediate(a,f,d)})},this.initWebGLObjects=function(a){for(a.__webglObjects||(a.__webglObjects=[],a.__webglObjectsImmediate=[],a.__webglSprites=[],a.__webglFlares=[]);a.__objectsAdded.length;)F(a.__objectsAdded[0],a),a.__objectsAdded.splice(0,1);for(;a.__objectsRemoved.length;)L(a.__objectsRemoved[0],a),a.__objectsRemoved.splice(0,1);for(var b=0,c=a.__webglObjects.length;c>b;b++){var d=a.__webglObjects[b].object;void 0===d.__webglInit&&(void 0!==d.__webglActive&&L(d,a),F(d,a)),I(d)}},this.initMaterial=function(a,b,c,d){a.addEventListener("dispose",Pb);var f,g,h,i,j,k,l;a instanceof e.MeshDepthMaterial?l="depth":a instanceof e.MeshNormalMaterial?l="normal":a instanceof e.MeshBasicMaterial?l="basic":a instanceof e.MeshLambertMaterial?l="lambert":a instanceof e.MeshPhongMaterial?l="phong":a instanceof e.MeshPhysicalMaterial?l="physical":a instanceof e.LineBasicMaterial?l="basic":a instanceof e.LineDashedMaterial?l="dashed":a instanceof e.ParticleSystemMaterial&&(l="particle_basic"),l&&e.ShaderLib[l]&&O(a,e.ShaderLib[l]),l||(l=a.shaderID),i=wa(b),k=xa(b),j=va(d),h={map:!!a.map,opacityMap:!!a.opacityMap,envMap:!!a.envMap,diffuseEnvMap:!!a.diffuseEnvMap,lightMap:!!a.lightMap,emissiveMap:!!a.emissiveMap,bumpMap:!!a.bumpMap,normalMap:!!a.normalMap,specularMap:!!a.specularMap,reflectivityMap:!!a.reflectivityMap,roughnessMap:!!a.roughnessMap,translucencyMap:!!a.translucencyMap,metallicMap:!!a.metallicMap,falloffMap:!!a.falloffMap,clearCoat:void 0!==a.clearCoat&&0!==a.clearCoat,anisotropy:void 0!==a.anisotropy&&0!==a.anisotropy||!!a.anisotropyMap,anisotropyMap:!!a.anisotropyMap,anisotropyRotation:void 0!==a.anisotropyRotation&&0!==a.anisotropyRotation||!!a.anisotropyRotationMap,anisotropyRotationMap:!!a.anisotropyRotationMap,vertexColors:a.vertexColors,fog:c,useFog:a.fog,fogExp:c instanceof e.FogExp2,sizeAttenuation:!!a.sizeAttenuation,skinning:a.skinning,maxBones:j,useVertexTexture:Fb&&d&&d.useVertexTexture,morphTargets:a.morphTargets,morphNormals:a.morphNormals,maxMorphTargets:this.maxMorphTargets,maxMorphNormals:this.maxMorphNormals,maxDirLights:i.directional,maxPointLights:i.point,maxSpotLights:i.spot,maxHemiLights:i.hemi,maxAreaLights:i.area,maxShadows:k,shadowMapEnabled:this.shadowMapEnabled&&d.receiveShadow&&k>0,shadowMapType:this.shadowMapType,shadowMapDebug:this.shadowMapDebug,shadowMapCascade:this.shadowMapCascade,translucency:a.translucency&&a.translucency.getHex()>0,alphaTest:a.alphaTest,falloff:a.falloff||!1,wrapAround:a.wrapAround,doubleSided:a.side===e.DoubleSide,flipSided:a.side===e.BackSide},a.program=ha(l,a.fragmentShader,a.vertexShader,a.uniforms,a.attributes,a.defines,h,a.index0AttributeName);var m=a.program.attributes;if(a.morphTargets){a.numSupportedMorphTargets=0;var n,o="morphTarget";for(g=0;g=0&&a.numSupportedMorphTargets++}if(a.morphNormals){a.numSupportedMorphNormals=0;var n,o="morphNormal";for(g=0;g=0&&a.numSupportedMorphNormals++}a.uniformsList=[];for(f in a.uniforms)a.uniformsList.push([a.uniforms[f],f])},this.setFaceCulling=function(a,b){a===e.CullFaceNone?Ka.disable(Ka.CULL_FACE):(b===e.FrontFaceDirectionCW?Ka.frontFace(Ka.CW):Ka.frontFace(Ka.CCW),a===e.CullFaceBack?Ka.cullFace(Ka.BACK):a===e.CullFaceFront?Ka.cullFace(Ka.FRONT):Ka.cullFace(Ka.FRONT_AND_BACK),Ka.enable(Ka.CULL_FACE))},this.setMaterialFaces=function(a){var b=a.side===e.DoubleSide,c=a.side===e.BackSide;$a!==b&&(b?Ka.disable(Ka.CULL_FACE):Ka.enable(Ka.CULL_FACE),$a=b),_a!==c&&(c?Ka.frontFace(Ka.CW):Ka.frontFace(Ka.CCW),_a=c)},this.setDepthTest=function(a){eb!==a&&(a?Ka.enable(Ka.DEPTH_TEST):Ka.disable(Ka.DEPTH_TEST),eb=a)},this.setDepthWrite=function(a){fb!==a&&(Ka.depthMask(a),fb=a)},this.setBlending=function(a,b,c,d){a!==ab&&(a===e.NoBlending?Ka.disable(Ka.BLEND):a===e.AdditiveBlending?(Ka.enable(Ka.BLEND),Ka.blendEquation(Ka.FUNC_ADD),Ka.blendFunc(Ka.SRC_ALPHA,Ka.ONE)):a===e.SubtractiveBlending?(Ka.enable(Ka.BLEND),Ka.blendEquation(Ka.FUNC_ADD),Ka.blendFunc(Ka.ZERO,Ka.ONE_MINUS_SRC_COLOR)):a===e.MultiplyBlending?(Ka.enable(Ka.BLEND),Ka.blendEquation(Ka.FUNC_ADD),Ka.blendFunc(Ka.ZERO,Ka.SRC_COLOR)):a===e.CustomBlending?Ka.enable(Ka.BLEND):(Ka.enable(Ka.BLEND),Ka.blendEquationSeparate(Ka.FUNC_ADD,Ka.FUNC_ADD),Ka.blendFuncSeparate(Ka.SRC_ALPHA,Ka.ONE_MINUS_SRC_ALPHA,Ka.ONE,Ka.ONE_MINUS_SRC_ALPHA)),ab=a),a===e.CustomBlending?(b!==bb&&(Ka.blendEquation(ua(b)),bb=b),c===cb&&d===db||(Ka.blendFunc(ua(c),ua(d)),cb=c,db=d)):(bb=null,cb=null,db=null)};var Vb=function(a,b){var c=Ka.getError();if(c!==Ka.NO_ERROR){var d="";d=c===Ka.OUT_OF_MEMORY?"OUT_OF_MEMORY":c===Ka.INVALID_ENUM?"INVALID_ENUM":c===Ka.INVALID_OPERATION?"INVALID_OPERATION":c===Ka.INVALID_VALUE?"INVALID_VALUE":c===Ka.INVALID_FRAMEBUFFER_OPERATION?"INVALID_FRAMEBUFFER_OPERATION":c===Ka.CONTEXT_LOST_WEBGL?"CONTEXT_LOST_WEBGL":c===Ka.NO_ERROR?"NO_ERROR":"Unknown code: "+c,e.onerror("WebGL Error: "+d+" ("+a+")",b)}};this.setTexture=function(a,b){if(a.needsUpdate){a.__webglInit||(a.__webglInit=!0,a.addEventListener("dispose",Nb),a.__webglTexture=Ka.createTexture(),Ra.info.memory.textures++),Ka.activeTexture(Ka.TEXTURE0+b),Ka.bindTexture(Ka.TEXTURE_2D,a.__webglTexture),Ka.pixelStorei(Ka.UNPACK_FLIP_Y_WEBGL,a.flipY),Ka.pixelStorei(Ka.UNPACK_PREMULTIPLY_ALPHA_WEBGL,a.premultiplyAlpha),Ka.pixelStorei(Ka.UNPACK_ALIGNMENT,a.unpackAlignment);var c=a.image,d=e.Math.isPowerOfTwo(c.width)&&e.Math.isPowerOfTwo(c.height),f=ua(a.format),g=ua(a.type);ma(Ka.TEXTURE_2D,a,d);var h,i=a.mipmaps;if(a instanceof e.DataTexture)if(i.length>0&&d){for(var j=0,k=i.length;k>j;j++)h=i[j],Ka.texImage2D(Ka.TEXTURE_2D,j,f,h.width,h.height,0,f,g,h.data),Vb("_gl.texImage2D DataTexture Mipmaps, texture.name: "+a.name,a);a.generateMipmaps=!1}else Ka.texImage2D(Ka.TEXTURE_2D,0,f,c.width,c.height,0,f,g,c.data),Vb("_gl.texImage2D DataTexture, texture.name: "+a.name,a);else if(a instanceof e.CompressedTexture)for(var j=0,k=i.length;k>j;j++)h=i[j],a.format!==e.RGBAFormat?(Ka.compressedTexImage2D(Ka.TEXTURE_2D,j,f,h.width,h.height,0,h.data),Vb("_gl.texImage2D CompressedTexture Non RGBA, texture.name: "+a.name,a)):(Ka.texImage2D(Ka.TEXTURE_2D,j,f,h.width,h.height,0,f,g,h.data),Vb("_gl.texImage2D CompressedTexture, texture.name: "+a.name,a));else if(i.length>0&&d){for(var j=0,k=i.length;k>j;j++)h=i[j],Ka.texImage2D(Ka.TEXTURE_2D,j,f,f,g,h),Vb("_gl.texImage2D Mipmaps, texture.name: "+a.name,a);a.generateMipmaps=!1}else Ka.texImage2D(Ka.TEXTURE_2D,0,f,f,g,a.image),Vb("_gl.texImage2D, texture.name: "+a.name,a);a.generateMipmaps&&d&&(Ka.generateMipmap(Ka.TEXTURE_2D),Vb("_gl.generateMipmap, texture.name: "+a.name,a)),a.needsUpdate=!1,a.onUpdate&&a.onUpdate()}else Ka.activeTexture(Ka.TEXTURE0+b),Ka.bindTexture(Ka.TEXTURE_2D,a.__webglTexture)},this.setRenderTarget=function(a){var b=a instanceof e.WebGLRenderTargetCube;if(a&&!a.__webglFramebuffer){void 0===a.depthBuffer&&(a.depthBuffer=!0),void 0===a.stencilBuffer&&(a.stencilBuffer=!0),a.addEventListener("dispose",Ob),a.__webglTexture=Ka.createTexture(),Ra.info.memory.textures++;var c=e.Math.isPowerOfTwo(a.width)&&e.Math.isPowerOfTwo(a.height),d=ua(a.format),f=ua(a.type);if(b){a.__webglFramebuffer=[],a.__webglRenderbuffer=[],Ka.bindTexture(Ka.TEXTURE_CUBE_MAP,a.__webglTexture),ma(Ka.TEXTURE_CUBE_MAP,a,c);for(var g=0;6>g;g++)a.__webglFramebuffer[g]=Ka.createFramebuffer(),a.__webglRenderbuffer[g]=Ka.createRenderbuffer(),Ka.texImage2D(Ka.TEXTURE_CUBE_MAP_POSITIVE_X+g,0,d,a.width,a.height,0,d,f,null),Vb("_gl.texImage2D CubeMap, renderTarget.name: "+a.name,a),qa(a.__webglFramebuffer[g],a,Ka.TEXTURE_CUBE_MAP_POSITIVE_X+g),ra(a.__webglRenderbuffer[g],a);c&&(Ka.generateMipmap(Ka.TEXTURE_CUBE_MAP),Vb("_gl.generateMipmap, CubeMap, renderTarget.name: "+a.name,a))}else{if(a.__webglFramebuffer=Ka.createFramebuffer(),a.shareDepthFrom?a.__webglRenderbuffer=a.shareDepthFrom.__webglRenderbuffer:a.__webglRenderbuffer=Ka.createRenderbuffer(),Ka.bindTexture(Ka.TEXTURE_2D,a.__webglTexture),ma(Ka.TEXTURE_2D,a,c),Ka.texImage2D(Ka.TEXTURE_2D,0,d,a.width,a.height,0,d,f,null),Vb("_gl.texImage2D, renderTarget.name: "+a.name,a),qa(a.__webglFramebuffer,a,Ka.TEXTURE_2D),a.shareDepthFrom){var h="glFormat: "+d+" glType: "+f;if(a.depthBuffer&&!a.stencilBuffer?(Ka.framebufferRenderbuffer(Ka.FRAMEBUFFER,Ka.DEPTH_ATTACHMENT,Ka.RENDERBUFFER,a.__webglRenderbuffer),h=" renderTarget: "+a.width+"+"+a.height+" DEPTH_ATTACHMENT"):a.depthBuffer&&a.stencilBuffer&&(Ka.framebufferRenderbuffer(Ka.FRAMEBUFFER,Ka.DEPTH_STENCIL_ATTACHMENT,Ka.RENDERBUFFER,a.__webglRenderbuffer),h=" renderTarget: "+a.width+"+"+a.height+" DEPTH_STENCIL_ATTACHMENT"),Ka.checkFramebufferStatus(Ka.FRAMEBUFFER)!=Ka.FRAMEBUFFER_COMPLETE)throw new Error("(B) Rendering to this texture (renderTarget.name: "+a.name+") is not supported (incomplete framebuffer) "+h)}else ra(a.__webglRenderbuffer,a);c&&(Ka.generateMipmap(Ka.TEXTURE_2D),Vb("_gl.generateMipmap, renderTarget.name: "+a.name,a))}b?Ka.bindTexture(Ka.TEXTURE_CUBE_MAP,null):Ka.bindTexture(Ka.TEXTURE_2D,null),Ka.bindRenderbuffer(Ka.RENDERBUFFER,null),Ka.bindFramebuffer(Ka.FRAMEBUFFER,null)}var i,j,k,l,m;a?(i=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,j=a.width,k=a.height,l=0,m=0):(i=null,j=mb,k=nb,l=kb,m=lb),i!==Va&&(Ka.bindFramebuffer(Ka.FRAMEBUFFER,i),Ka.viewport(l,m,j,k),Va=i),ob=j,pb=k},this.shadowMapPlugin=new e.ShadowMapPlugin,this.addPrePlugin(this.shadowMapPlugin),this.addPostPlugin(new e.SpritePlugin),this.addPostPlugin(new e.LensFlarePlugin)},e.WebGLRenderTarget=function(a,b,c,d){this.name=d||"",this.width=a,this.height=b,c=c||{},this.wrapS=void 0!==c.wrapS?c.wrapS:e.ClampToEdgeWrapping,this.wrapT=void 0!==c.wrapT?c.wrapT:e.ClampToEdgeWrapping,this.magFilter=void 0!==c.magFilter?c.magFilter:e.LinearFilter,this.minFilter=void 0!==c.minFilter?c.minFilter:e.LinearMipMapLinearFilter,this.anisotropy=void 0!==c.anisotropy?c.anisotropy:1,this.offset=new e.Vector2(0,0),this.repeat=new e.Vector2(1,1),this.format=void 0!==c.format?c.format:e.RGBAFormat,this.type=void 0!==c.type?c.type:e.UnsignedByteType,this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0,this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0,this.generateMipmaps=void 0!==c.generateMipmaps?c.generateMipmaps:!1,this.shareDepthFrom=null},e.WebGLRenderTarget.prototype={constructor:e.WebGLRenderTarget,clone:function(){var a=new e.WebGLRenderTarget(this.width,this.height,null,this.name+" Clone");return a.wrapS=this.wrapS,a.wrapT=this.wrapT,a.magFilter=this.magFilter,a.minFilter=this.minFilter,a.anisotropy=this.anisotropy,a.offset.copy(this.offset),a.repeat.copy(this.repeat),a.format=this.format,a.type=this.type,a.depthBuffer=this.depthBuffer,a.stencilBuffer=this.stencilBuffer,a.generateMipmaps=this.generateMipmaps,a.shareDepthFrom=this.shareDepthFrom,a},dispose:function(){this.dispatchEvent({type:"dispose"})}},e.EventDispatcher.prototype.apply(e.WebGLRenderTarget.prototype),e.WebGLRenderTargetCube=function(a,b,c){e.WebGLRenderTarget.call(this,a,b,c),this.activeCubeFace=0},e.WebGLRenderTargetCube.prototype=Object.create(e.WebGLRenderTarget.prototype),e.RenderableVertex=function(){this.position=new e.Vector3,this.positionWorld=new e.Vector3,this.positionScreen=new e.Vector4,this.visible=!0},e.RenderableVertex.prototype.copy=function(a){this.positionWorld.copy(a.positionWorld),this.positionScreen.copy(a.positionScreen)},e.RenderableFace=function(){this.id=0,this.v1=new e.RenderableVertex,this.v2=new e.RenderableVertex,this.v3=new e.RenderableVertex,this.centroidModel=new e.Vector3,this.normalModel=new e.Vector3,this.vertexNormalsModel=[new e.Vector3,new e.Vector3,new e.Vector3],this.vertexNormalsLength=0,this.color=null,this.material=null,this.uvs=[[]],this.z=0},e.RenderableObject=function(){this.id=0,this.object=null,this.z=0},e.RenderableSprite=function(){this.id=0,this.object=null,this.x=0,this.y=0,this.z=0,this.rotation=0,this.scale=new e.Vector2,this.material=null},e.RenderableLine=function(){this.id=0,this.v1=new e.RenderableVertex,this.v2=new e.RenderableVertex,this.vertexColors=[new e.Color,new e.Color],this.material=null,this.z=0},e.GeometryUtils={merge:function(a,b,c){var d,f,g=a.vertices.length,h=(a.faceVertexUvs[0].length,b instanceof e.Mesh?b.geometry:b),i=a.vertices,j=h.vertices,k=a.faces,l=h.faces,m=a.faceVertexUvs[0],n=h.faceVertexUvs[0];void 0===c&&(c=0),b instanceof e.Mesh&&(b.matrixAutoUpdate&&b.updateMatrix(),d=b.matrix,f=(new e.Matrix3).getNormalMatrix(d));for(var o=0,p=j.length;p>o;o++){var q=j[o],r=q.clone();d&&r.applyMatrix4(d),i.push(r)}for(o=0,p=l.length;p>o;o++){var s,t,u,v=l[o],w=v.vertexNormals,x=v.vertexColors;s=new e.Face3(v.a+g,v.b+g,v.c+g),s.normal.copy(v.normal),f&&s.normal.applyMatrix3(f).normalize();for(var y=0,z=w.length;z>y;y++)t=w[y].clone(),f&&t.applyMatrix3(f).normalize(),s.vertexNormals.push(t);s.color.copy(v.color);for(var y=0,z=x.length;z>y;y++)u=x[y],s.vertexColors.push(u.clone());s.materialIndex=v.materialIndex+c,s.centroid.copy(v.centroid),d&&s.centroid.applyMatrix4(d),k.push(s)}for(o=0,p=n.length;p>o;o++){for(var A=n[o],B=[],y=0,z=A.length;z>y;y++)B.push(new e.Vector2(A[y].x,A[y].y));m.push(B)}},randomPointInTriangle:function(){var a=new e.Vector3;return function(b,c,d){var f=new e.Vector3,g=e.Math.random16(),h=e.Math.random16();g+h>1&&(g=1-g,h=1-h);var i=1-g-h;return f.copy(b),f.multiplyScalar(g),a.copy(c),a.multiplyScalar(h),f.add(a),a.copy(d),a.multiplyScalar(i),f.add(a),f}}(),randomPointInFace:function(a,b,c){var d,f,g;return d=b.vertices[a.a],f=b.vertices[a.b],g=b.vertices[a.c],e.GeometryUtils.randomPointInTriangle(d,f,g)},randomPointsInGeometry:function(a,b){function c(a){function b(c,d){if(c>d)return c;var e=c+Math.floor((d-c)/2);return n[e]>a?b(c,e-1):n[e]f;f++)d=j[f],g=k[d.a],h=k[d.b],i=k[d.c],d._area=e.GeometryUtils.triangleArea(g,h,i),m+=d._area,n[f]=m;var o,p,q=[],r={};for(f=0;b>f;f++)o=e.Math.random16()*m,p=c(o),q[f]=e.GeometryUtils.randomPointInFace(j[p],a,!0),r[p]?r[p]+=1:r[p]=1;return q},triangleArea:function(){var a=new e.Vector3,b=new e.Vector3;return function(c,d,e){return a.subVectors(d,c),b.subVectors(e,c),a.cross(b),.5*a.length()}}(),center:function(a){a.computeBoundingBox();var b=a.boundingBox,c=new e.Vector3;return c.addVectors(b.min,b.max),c.multiplyScalar(-.5),a.applyMatrix((new e.Matrix4).makeTranslation(c.x,c.y,c.z)),a.computeBoundingBox(),c},triangulateQuads:function(a){var b,c,d,e,f=[],g=[];for(b=0,c=a.faceVertexUvs.length;c>b;b++)g[b]=[];for(b=0,c=a.faces.length;c>b;b++){var h=a.faces[b];for(f.push(h),d=0,e=a.faceVertexUvs.length;e>d;d++)g[d].push(a.faceVertexUvs[d][b])}a.faces=f,a.faceVertexUvs=g,a.computeCentroids(),a.computeFaceNormals(),a.computeVertexNormals(),a.hasTangents&&a.computeTangents()}},e.ImageUtils={crossOrigin:void 0,loadTexture:function(a,b,c,d){var f=new e.ImageLoader;f.crossOrigin=this.crossOrigin;var g=new e.Texture(void 0,b),h=f.load(a,function(){g.needsUpdate=!0,c&&c(g)});return g.image=h,g.sourceFile=a,g},loadCompressedTexture:function(a,b,c,d){var f=new e.CompressedTexture;f.mapping=b;var g=new XMLHttpRequest;return g.onload=function(){var a=g.response,b=e.ImageUtils.parseDDS(a,!0);f.format=b.format,f.mipmaps=b.mipmaps,f.image.width=b.width,f.image.height=b.height,f.generateMipmaps=!1,f.needsUpdate=!0,c&&c(f)},g.onerror=d,g.open("GET",a,!0),g.responseType="arraybuffer",g.send(null),f},loadTextureCube:function(a,b,c,d){var f=[];f.loadCount=0;var g=new e.Texture;g.image=f,void 0!==b&&(g.mapping=b),g.flipY=!1;for(var h=0,i=a.length;i>h;++h){var j=new Image;f[h]=j,j.onload=function(){f.loadCount+=1,6===f.loadCount&&(g.needsUpdate=!0,c&&c(g))},j.onerror=d,j.crossOrigin=this.crossOrigin,j.src=a[h]}return g},loadCompressedTextureCube:function(a,b,c,d){var f=[];f.loadCount=0;var g=new e.CompressedTexture;g.image=f,void 0!==b&&(g.mapping=b),g.flipY=!1,g.generateMipmaps=!1;var h=function(a,b){return function(){var d=a.response,h=e.ImageUtils.parseDDS(d,!0);b.format=h.format,b.mipmaps=h.mipmaps,b.width=h.width,b.height=h.height,f.loadCount+=1,6===f.loadCount&&(g.format=h.format,g.needsUpdate=!0,c&&c(g))}};if(a instanceof Array)for(var i=0,j=a.length;j>i;++i){var k={};f[i]=k;var l=new XMLHttpRequest;l.onload=h(l,k),l.onerror=d;var m=a[i];l.open("GET",m,!0),l.responseType="arraybuffer",l.send(null)}else{var m=a,l=new XMLHttpRequest;l.onload=function(){var a=l.response,b=e.ImageUtils.parseDDS(a,!0);if(b.isCubemap){for(var d=b.mipmaps.length/b.mipmapCount,h=0;d>h;h++){f[h]={mipmaps:[]};for(var i=0;ii;i++){f[i]={mipmaps:[]};for(var j=0;j>8&255,a>>16&255,a>>24&255)}function f(a,b,c,d){for(var e=c*d*4,f=new Uint8Array(a,b,e),g=new Uint8Array(e),h=0,i=0,j=0;d>j;j++)for(var k=0;c>k;k++){var l=f[i];i++;var m=f[i];i++;var n=f[i];i++;var o=f[i];i++,g[h]=n,h++,g[h]=m,h++,g[h]=l,h++,g[h]=o,h++}return g}var g={mipmaps:[],width:0,height:0,format:null,mipmapCount:1},h=542327876,i=131072,j=512,k=4,l=c("DXT1"),m=c("DXT3"),n=c("DXT5"),o=31,p=0,q=1,r=2,s=3,t=4,u=7,v=20,w=21,x=22,y=23,z=24,A=25,B=26,C=28,D=new Int32Array(a,0,o);if(D[p]!==h)return e.onerror("ImageUtils.parseDDS(): Invalid magic number in DDS header"),g;if(!D[v]&k)return e.onerror("ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code"),g;var E,F=D[w],G=!1;switch(F){case l:E=8,g.format=e.RGB_S3TC_DXT1_Format;break;case m:E=16,g.format=e.RGBA_S3TC_DXT3_Format;break;case n:E=16,g.format=e.RGBA_S3TC_DXT5_Format;break;default:if(!(32==D[x]&&16711680&D[y]&&65280&D[z]&&255&D[A]&&4278190080&D[B]))return e.onerror("ImageUtils.parseDDS(): Unsupported FourCC code: ",d(F)),g;G=!0,E=64,g.format=e.RGBAFormat}g.mipmapCount=1,D[r]&i&&b!==!1&&(g.mipmapCount=Math.max(1,D[u])),g.isCubemap=!!(D[C]&j),g.width=D[t],g.height=D[s];for(var H=D[q]+4,I=g.width,J=g.height,K=g.isCubemap?6:1,L=0;K>L;L++){for(var M=0;Mm;m++)for(var n=0;g>n;n++){var o=0>n-1?0:n-1,p=n+1>g-1?g-1:n+1,q=0>m-1?0:m-1,r=m+1>f-1?f-1:m+1,s=[],t=[0,0,j[4*(n*f+m)]/255*b];s.push([-1,0,j[4*(n*f+q)]/255*b]),s.push([-1,-1,j[4*(o*f+q)]/255*b]),s.push([0,-1,j[4*(o*f+m)]/255*b]),s.push([1,-1,j[4*(o*f+r)]/255*b]),s.push([1,0,j[4*(n*f+r)]/255*b]),s.push([1,1,j[4*(p*f+r)]/255*b]),s.push([0,1,j[4*(p*f+m)]/255*b]),s.push([-1,1,j[4*(p*f+q)]/255*b]);for(var u=[],v=s.length,w=0;v>w;w++){var x=s[w],y=s[(w+1)%v];x=d(x,t),y=d(y,t),u.push(e(c(x,y)))}for(var z=[0,0,0],w=0;wj;j++)f[3*j]=g,f[3*j+1]=h,f[3*j+2]=i;var k=new e.DataTexture(f,a,b,e.RGBFormat);return k.needsUpdate=!0,k}},e.SceneUtils={createMultiMaterialObject:function(a,b){for(var c=new e.Object3D,d=0,f=b.length;f>d;d++)c.add(new e.Mesh(a,b[d]));return c},detach:function(a,b,c){a.applyMatrix(b.matrixWorld),b.remove(a),c.add(a)},attach:function(a,b,c){var d=new e.Matrix4;d.getInverse(c.matrixWorld),a.applyMatrix(d),b.remove(a),c.add(a)}},e.FontUtils={faces:{},face:"helvetiker",weight:"normal",style:"normal",size:150,divisions:10,getFace:function(){return this.faces[this.face][this.weight][this.style]},loadFace:function(a){var b=a.familyName.toLowerCase(),c=this;c.faces[b]=c.faces[b]||{},c.faces[b][a.cssFontWeight]=c.faces[b][a.cssFontWeight]||{},c.faces[b][a.cssFontWeight][a.cssFontStyle]=a;c.faces[b][a.cssFontWeight][a.cssFontStyle]=a;return a},drawText:function(a){var b,c=this.getFace(),d=this.size/c.resolution,f=0,g=String(a).split(""),h=g.length,i=[];for(b=0;h>b;b++){var j=new e.Path,k=this.extractGlyphPoints(g[b],c,d,f,j);f+=k.offset,i.push(k.path)}var l=f/2;return{paths:i,offset:l}},extractGlyphPoints:function(a,b,c,d,f){var g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z=[],A=b.glyphs[a]||b.glyphs["?"];if(A){if(A.o)for(j=A._cachedOutline||(A._cachedOutline=A.o.split(" ")),l=j.length,m=c,n=c,g=0;l>g;)switch(k=j[g++]){case"m":o=j[g++]*m+d,p=j[g++]*n,f.moveTo(o,p);break;case"l":o=j[g++]*m+d,p=j[g++]*n,f.lineTo(o,p);break;case"q":if(q=j[g++]*m+d,r=j[g++]*n,u=j[g++]*m+d,v=j[g++]*n,f.quadraticCurveTo(u,v,q,r),y=z[z.length-1])for(s=y.x,t=y.y,h=1,i=this.divisions;i>=h;h++){var B=h/i;e.Shape.Utils.b2(B,s,u,q),e.Shape.Utils.b2(B,t,v,r)}break;case"b":if(q=j[g++]*m+d,r=j[g++]*n,u=j[g++]*m+d,v=j[g++]*-n,w=j[g++]*m+d,x=j[g++]*-n,f.bezierCurveTo(q,r,u,v,w,x),y=z[z.length-1])for(s=y.x,t=y.y,h=1,i=this.divisions;i>=h;h++){var B=h/i;e.Shape.Utils.b3(B,s,u,w,q),e.Shape.Utils.b3(B,t,v,x,r)}}return{offset:A.ha*c,path:f}}}},e.FontUtils.generateShapes=function(a,b){b=b||{};var c=void 0!==b.size?b.size:100,d=void 0!==b.curveSegments?b.curveSegments:4,f=void 0!==b.font?b.font:"helvetiker",g=void 0!==b.weight?b.weight:"normal",h=void 0!==b.style?b.style:"normal";e.FontUtils.size=c,e.FontUtils.divisions=d,e.FontUtils.face=f,e.FontUtils.weight=g,e.FontUtils.style=h;for(var i=e.FontUtils.drawText(a),j=i.paths,k=[],l=0,m=j.length;m>l;l++)Array.prototype.push.apply(k,j[l].toShapes());return k},function(a){var b=1e-10,c=function(a,b){var c=a.length;if(3>c)return null;var g,h,i,j=[],k=[],l=[];if(d(a)>0)for(h=0;c>h;h++)k[h]=h;else for(h=0;c>h;h++)k[h]=c-1-h;var m=c,n=2*m;for(h=m-1;m>2;){if(n--<=0)return e.onwarning("Warning, unable to triangulate polygon!"),b?l:j;if(g=h,g>=m&&(g=0),h=g+1,h>=m&&(h=0),i=h+1,i>=m&&(i=0),f(a,g,h,i,m,k)){var o,p,q,r,s;for(o=k[g],p=k[h],q=k[i],j.push([a[o],a[p],a[q]]),l.push([k[g],k[h],k[i]]),r=h,s=h+1;m>s;r++,s++)k[r]=k[s];m--,n=2*m}}return b?l:j},d=function(a){for(var b=a.length,c=0,d=b-1,e=0;b>e;d=e++)c+=a[d].x*a[e].y-a[e].x*a[d].y;return.5*c},f=function(a,c,d,e,f,g){var h,i,j,k,l,m,n,o,p;if(i=a[g[c]].x,j=a[g[c]].y,k=a[g[d]].x,l=a[g[d]].y,m=a[g[e]].x,n=a[g[e]].y,b>(k-i)*(n-j)-(l-j)*(m-i))return!1;var q,r,s,t,u,v,w,x,y,z,A,B,C,D,E;for(q=m-k,r=n-l,s=i-m,t=j-n,u=k-i,v=l-j,h=0;f>h;h++)if(o=a[g[h]].x,p=a[g[h]].y,!(o===i&&p===j||o===k&&p===l||o===m&&p===n)&&(w=o-i,x=p-j,y=o-k,z=p-l,A=o-m,B=p-n,E=q*z-r*y,C=u*x-v*w,D=s*B-t*A,E>=-b&&D>=-b&&C>=-b))return!1;return!0};return a.Triangulate=c,a.Triangulate.area=d,a}(e.FontUtils),d._typeface_js={faces:e.FontUtils.faces,loadFace:e.FontUtils.loadFace},e.typeface_js=d._typeface_js,e.Curve=function(){},e.Curve.prototype.getPoint=function(a){return e.onwarning("Warning, getPoint() not implemented!"),null},e.Curve.prototype.getPointAt=function(a){var b=this.getUtoTmapping(a);return this.getPoint(b)},e.Curve.prototype.getPoints=function(a){a||(a=5);var b,c=[];for(b=0;a>=b;b++)c.push(this.getPoint(b/a));return c},e.Curve.prototype.getSpacedPoints=function(a){a||(a=5);var b,c=[];for(b=0;a>=b;b++)c.push(this.getPointAt(b/a));return c},e.Curve.prototype.getLength=function(){var a=this.getLengths();return a[a.length-1]},e.Curve.prototype.getLengths=function(a){if(a||(a=this.__arcLengthDivisions?this.__arcLengthDivisions:200),this.cacheArcLengths&&this.cacheArcLengths.length==a+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;var b,c,d=[],e=this.getPoint(0),f=0;for(d.push(0),c=1;a>=c;c++)b=this.getPoint(c/a),f+=b.distanceTo(e),d.push(f),e=b;return this.cacheArcLengths=d,d},e.Curve.prototype.updateArcLengths=function(){this.needsUpdate=!0,this.getLengths()},e.Curve.prototype.getUtoTmapping=function(a,b){var c,d=this.getLengths(),e=0,f=d.length;c=b?b:a*d[f-1];for(var g,h=0,i=f-1;i>=h;)if(e=Math.floor(h+(i-h)/2),g=d[e]-c,0>g)h=e+1;else{if(!(g>0)){i=e;break}i=e-1}if(e=i,d[e]==c){var j=e/(f-1);return j}var k=d[e],l=d[e+1],m=l-k,n=(c-k)/m,j=(e+n)/(f-1);return j},e.Curve.prototype.getTangent=function(a){var b=1e-4,c=a-b,d=a+b;0>c&&(c=0),d>1&&(d=1);var e=this.getPoint(c),f=this.getPoint(d),g=f.clone().sub(e);return g.normalize()},e.Curve.prototype.getTangentAt=function(a){var b=this.getUtoTmapping(a);return this.getTangent(b)},e.Curve.Utils={tangentQuadraticBezier:function(a,b,c,d){return 2*(1-a)*(c-b)+2*a*(d-c)},tangentCubicBezier:function(a,b,c,d,e){return-3*b*(1-a)*(1-a)+3*c*(1-a)*(1-a)-6*a*c*(1-a)+6*a*d*(1-a)-3*a*a*d+3*a*a*e},tangentSpline:function(a,b,c,d,e){var f=6*a*a-6*a,g=3*a*a-4*a+1,h=-6*a*a+6*a,i=3*a*a-2*a;return f+g+h+i},interpolate:function(a,b,c,d,e){var f=.5*(c-a),g=.5*(d-b),h=e*e,i=e*h;return(2*b-2*c+f+g)*i+(-3*b+3*c-2*f-g)*h+f*e+b}},e.Curve.create=function(a,b){return a.prototype=Object.create(e.Curve.prototype),a.prototype.getPoint=b,a},e.CurvePath=function(){this.curves=[],this.bends=[],this.autoClose=!1},e.CurvePath.prototype=Object.create(e.Curve.prototype),e.CurvePath.prototype.add=function(a){this.curves.push(a)},e.CurvePath.prototype.checkConnection=function(){},e.CurvePath.prototype.closePath=function(){var a=this.curves[0].getPoint(0),b=this.curves[this.curves.length-1].getPoint(1);a.equals(b)||this.curves.push(new e.LineCurve(b,a))},e.CurvePath.prototype.getPoint=function(a){for(var b,c,d=a*this.getLength(),e=this.getCurveLengths(),f=0;f=d){b=e[f]-d,c=this.curves[f];var g=1-b/c.getLength();return c.getPointAt(g)}f++}return null},e.CurvePath.prototype.getLength=function(){var a=this.getCurveLengths();return a[a.length-1]},e.CurvePath.prototype.getCurveLengths=function(){if(this.cacheLengths&&this.cacheLengths.length==this.curves.length)return this.cacheLengths;var a,b=[],c=0,d=this.curves.length;for(a=0;d>a;a++)c+=this.curves[a].getLength(),b.push(c);return this.cacheLengths=b,b},e.CurvePath.prototype.getBoundingBox=function(){var a,b,c,d,f,g,h=this.getPoints();a=b=Number.NEGATIVE_INFINITY,d=f=Number.POSITIVE_INFINITY;var i,j,k,l,m=h[0]instanceof e.Vector3;for(l=m?new e.Vector3:new e.Vector2,j=0,k=h.length;k>j;j++)i=h[j],i.x>a?a=i.x:i.xb?b=i.y:i.yc?c=i.z:i.zc;c++)e=this.getWrapPoints(e,b[c]);return e},e.CurvePath.prototype.getTransformedSpacedPoints=function(a,b){var c,d,e=this.getSpacedPoints(a);for(b||(b=this.bends),c=0,d=b.length;d>c;c++)e=this.getWrapPoints(e,b[c]);return e},e.CurvePath.prototype.getWrapPoints=function(a,b){var c,d,e,f,g,h,i=this.getBoundingBox();for(c=0,d=a.length;d>c;c++){e=a[c],f=e.x,g=e.y,h=f/i.maxX,h=b.getUtoTmapping(h,f);var j=b.getPoint(h),k=b.getTangent(h);k.set(-k.y,k.x).multiplyScalar(g),e.x=j.x+k.x,e.y=j.y+k.y}return a},e.Gyroscope=function(){e.Object3D.call(this)},e.Gyroscope.prototype=Object.create(e.Object3D.prototype),e.Gyroscope.prototype.updateMatrixWorld=function(a){this.matrixAutoUpdate&&this.updateMatrix(),(this.matrixWorldNeedsUpdate||a)&&(this.parent?(this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix),this.matrixWorld.decompose(this.translationWorld,this.quaternionWorld,this.scaleWorld),this.matrix.decompose(this.translationObject,this.quaternionObject,this.scaleObject),this.matrixWorld.compose(this.translationWorld,this.quaternionObject,this.scaleWorld)):this.matrixWorld.copy(this.matrix),this.matrixWorldNeedsUpdate=!1,a=!0);for(var b=0,c=this.children.length;c>b;b++)this.children[b].updateMatrixWorld(a)},e.Gyroscope.prototype.translationWorld=new e.Vector3,e.Gyroscope.prototype.translationObject=new e.Vector3,e.Gyroscope.prototype.quaternionWorld=new e.Quaternion,e.Gyroscope.prototype.quaternionObject=new e.Quaternion,e.Gyroscope.prototype.scaleWorld=new e.Vector3,e.Gyroscope.prototype.scaleObject=new e.Vector3,e.Path=function(a){e.CurvePath.call(this),this.actions=[],a&&this.fromPoints(a)},e.Path.prototype=Object.create(e.CurvePath.prototype),e.PathActions={MOVE_TO:"moveTo",LINE_TO:"lineTo",QUADRATIC_CURVE_TO:"quadraticCurveTo",BEZIER_CURVE_TO:"bezierCurveTo",CSPLINE_THRU:"splineThru",ARC:"arc",ELLIPSE:"ellipse"},e.Path.prototype.fromPoints=function(a){this.moveTo(a[0].x,a[0].y);for(var b=1,c=a.length;c>b;b++)this.lineTo(a[b].x,a[b].y)},e.Path.prototype.moveTo=function(a,b){var c=Array.prototype.slice.call(arguments);this.actions.push({action:e.PathActions.MOVE_TO,args:c})},e.Path.prototype.lineTo=function(a,b){var c=Array.prototype.slice.call(arguments),d=this.actions[this.actions.length-1].args,f=d[d.length-2],g=d[d.length-1],h=new e.LineCurve(new e.Vector2(f,g),new e.Vector2(a,b));this.curves.push(h),this.actions.push({action:e.PathActions.LINE_TO,args:c})},e.Path.prototype.quadraticCurveTo=function(a,b,c,d){var f=Array.prototype.slice.call(arguments),g=this.actions[this.actions.length-1].args,h=g[g.length-2],i=g[g.length-1],j=new e.QuadraticBezierCurve(new e.Vector2(h,i),new e.Vector2(a,b),new e.Vector2(c,d));this.curves.push(j),this.actions.push({action:e.PathActions.QUADRATIC_CURVE_TO,args:f})},e.Path.prototype.bezierCurveTo=function(a,b,c,d,f,g){var h=Array.prototype.slice.call(arguments),i=this.actions[this.actions.length-1].args,j=i[i.length-2],k=i[i.length-1],l=new e.CubicBezierCurve(new e.Vector2(j,k),new e.Vector2(a,b),new e.Vector2(c,d),new e.Vector2(f,g));this.curves.push(l),this.actions.push({action:e.PathActions.BEZIER_CURVE_TO,args:h})},e.Path.prototype.splineThru=function(a){var b=Array.prototype.slice.call(arguments),c=this.actions[this.actions.length-1].args,d=c[c.length-2],f=c[c.length-1],g=[new e.Vector2(d,f)];Array.prototype.push.apply(g,a);var h=new e.SplineCurve(g);this.curves.push(h),this.actions.push({action:e.PathActions.CSPLINE_THRU,args:b})},e.Path.prototype.arc=function(a,b,c,d,e,f){var g=this.actions[this.actions.length-1].args,h=g[g.length-2],i=g[g.length-1];this.absarc(a+h,b+i,c,d,e,f)},e.Path.prototype.absarc=function(a,b,c,d,e,f){this.absellipse(a,b,c,c,d,e,f)},e.Path.prototype.ellipse=function(a,b,c,d,e,f,g){var h=this.actions[this.actions.length-1].args,i=h[h.length-2],j=h[h.length-1];this.absellipse(a+i,b+j,c,d,e,f,g)},e.Path.prototype.absellipse=function(a,b,c,d,f,g,h){var i=Array.prototype.slice.call(arguments),j=new e.EllipseCurve(a,b,c,d,f,g,h);this.curves.push(j);var k=j.getPoint(1);i.push(k.x),i.push(k.y),this.actions.push({action:e.PathActions.ELLIPSE,args:i})},e.Path.prototype.getSpacedPoints=function(a,b){a||(a=40);for(var c=[],d=0;a>d;d++)c.push(this.getPoint(d/a));return c},e.Path.prototype.getPoints=function(a,b){if(this.useSpacedPoints)return console.log("tata"),this.getSpacedPoints(a,b);a=a||12;var c,d,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v=[];for(c=0,d=this.actions.length;d>c;c++)switch(f=this.actions[c],g=f.action,h=f.args,g){case e.PathActions.MOVE_TO:v.push(new e.Vector2(h[0],h[1]));break;case e.PathActions.LINE_TO:v.push(new e.Vector2(h[0],h[1]));break;case e.PathActions.QUADRATIC_CURVE_TO:for(i=h[2],j=h[3],m=h[0],n=h[1],v.length>0?(q=v[v.length-1],o=q.x,p=q.y):(q=this.actions[c-1].args,o=q[q.length-2],p=q[q.length-1]),r=1;a>=r;r++)s=r/a,t=e.Shape.Utils.b2(s,o,m,i),u=e.Shape.Utils.b2(s,p,n,j),v.push(new e.Vector2(t,u));break;case e.PathActions.BEZIER_CURVE_TO:for(i=h[4],j=h[5],m=h[0],n=h[1],k=h[2],l=h[3],v.length>0?(q=v[v.length-1],o=q.x,p=q.y):(q=this.actions[c-1].args,o=q[q.length-2],p=q[q.length-1]),r=1;a>=r;r++)s=r/a,t=e.Shape.Utils.b3(s,o,m,k,i),u=e.Shape.Utils.b3(s,p,n,l,j),v.push(new e.Vector2(t,u));break;case e.PathActions.CSPLINE_THRU:q=this.actions[c-1].args;var w=new e.Vector2(q[q.length-2],q[q.length-1]),x=[w],y=a*h[0].length;x=x.concat(h[0]);var z=new e.SplineCurve(x);for(r=1;y>=r;r++)v.push(z.getPointAt(r/y));break;case e.PathActions.ARC:var A,B=h[0],C=h[1],D=h[2],E=h[3],F=h[4],G=!!h[5],H=F-E,I=2*a;for(r=1;I>=r;r++)s=r/I,G||(s=1-s),A=E+s*H,t=B+D*Math.cos(A),u=C+D*Math.sin(A),v.push(new e.Vector2(t,u));break;case e.PathActions.ELLIPSE:var A,B=h[0],C=h[1],J=h[2],K=h[3],E=h[4],F=h[5],G=!!h[6],H=F-E,I=2*a;for(r=1;I>=r;r++)s=r/I,G||(s=1-s),A=E+s*H,t=B+J*Math.cos(A),u=C+K*Math.sin(A),v.push(new e.Vector2(t,u))}var L=v[v.length-1],M=1e-10;return Math.abs(L.x-v[0].x)g;f=g++){var h=b[f],i=b[g],j=i.x-h.x,k=i.y-h.y;if(Math.abs(k)>c){if(0>k&&(h=b[g],j=-j,i=b[f],k=-k),a.yi.y)continue;if(a.y==h.y){if(a.x==h.x)return!0}else{var l=k*(a.x-h.x)-j*(a.y-h.y);if(0==l)return!0;if(0>l)continue;e=!e}}else{if(a.y!=h.y)continue;if(i.x<=a.x&&a.x<=h.x||h.x<=a.x&&a.x<=i.x)return!0}}return e}var c,d,f,g,h,i=[],j=new e.Path;for(c=0,d=this.actions.length;d>c;c++)f=this.actions[c],h=f.args,g=f.action,g==e.PathActions.MOVE_TO&&0!=j.actions.length&&(i.push(j),j=new e.Path),j[g].apply(j,h);if(0!=j.actions.length&&i.push(j),0==i.length)return[];var k,l,m,n=[];if(1==i.length)return l=i[0],m=new e.Shape,m.actions=l.actions, +m.curves=l.curves,n.push(m),n;var o=!e.Shape.Utils.isClockWise(i[0].getPoints());o=a?!o:o;var p,q=[],r=[],s=[],t=0;for(r[t]=void 0,s[t]=[],c=0,d=i.length;d>c;c++)l=i[c],p=l.getPoints(),k=e.Shape.Utils.isClockWise(p),k=a?!k:k,k?(!o&&r[t]&&t++,r[t]={s:new e.Shape,p:p},r[t].s.actions=l.actions,r[t].s.curves=l.curves,o&&t++,s[t]=[]):s[t].push({h:l,p:p[0]});if(r.length>1){for(var u=!1,v=[],w=0,x=r.length;x>w;w++)q[w]=[];for(var w=0,x=r.length;x>w;w++)for(var y=(r[w],s[w]),z=0;z0&&(u||(s=q))}var D,E,F;for(c=0,d=r.length;d>c;c++)for(m=r[c].s,n.push(m),D=s[c],E=0,F=D.length;F>E;E++)m.holes.push(D[E].h);return n},e.Shape=function(){e.Path.apply(this,arguments),this.holes=[]},e.Shape.prototype=Object.create(e.Path.prototype),e.Shape.prototype.extrude=function(a){var b=new e.ExtrudeGeometry(this,a);return b},e.Shape.prototype.makeGeometry=function(a){var b=new e.ShapeGeometry(this,a);return b},e.Shape.prototype.getPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;c>b;b++)d[b]=this.holes[b].getTransformedPoints(a,this.bends);return d},e.Shape.prototype.getSpacedPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;c>b;b++)d[b]=this.holes[b].getTransformedSpacedPoints(a,this.bends);return d},e.Shape.prototype.extractAllPoints=function(a){return{shape:this.getTransformedPoints(a),holes:this.getPointsHoles(a)}},e.Shape.prototype.extractPoints=function(a){return this.useSpacedPoints?this.extractAllSpacedPoints(a):this.extractAllPoints(a)},e.Shape.prototype.extractAllSpacedPoints=function(a){return{shape:this.getTransformedSpacedPoints(a),holes:this.getSpacedPointsHoles(a)}},e.Shape.Utils={triangulateShape:function(a,b){function c(a,b,c){return a.x!=b.x?a.xg){var p;if(n>0){if(0>o||o>n)return[];if(p=k*l-j*m,0>p||p>n)return[]}else{if(o>0||n>o)return[];if(p=k*l-j*m,p>0||n>p)return[]}if(0==p)return!f||0!=o&&o!=n?[a]:[];if(p==n)return!f||0!=o&&o!=n?[b]:[];if(0==o)return[d];if(o==n)return[e];var q=p/n;return[{x:a.x+q*h,y:a.y+q*i}]}if(0!=o||k*l!=j*m)return[];var r=0==h&&0==i,s=0==j&&0==k;if(r&&s)return a.x!=d.x||a.y!=d.y?[]:[a];if(r)return c(d,e,a)?[a]:[];if(s)return c(a,b,d)?[d]:[];var t,u,v,w,x,y,z,A;return 0!=h?(a.x=v?z>w?[]:w==z?f?[]:[x]:A>=w?[x,u]:[x,y]:v>A?[]:v==A?f?[]:[t]:A>=w?[t,u]:[t,y]}function f(a,b,c,d){var e=1e-10,f=b.x-a.x,g=b.y-a.y,h=c.x-a.x,i=c.y-a.y,j=d.x-a.x,k=d.y-a.y,l=f*i-g*h,m=f*k-g*j;if(Math.abs(l)>e){var n=j*i-k*h;return l>0?m>=0&&n>=0:m>=0||n>=0}return m>0}function g(a,b){function c(a,b){var c=s.length-1,d=a-1;0>d&&(d=c);var e=a+1;e>c&&(e=0);var g=f(s[a],s[d],s[e],h[b]);if(!g)return!1;var i=h.length-1,j=b-1;0>j&&(j=i);var k=b+1;return k>i&&(k=0),g=f(h[b],h[j],h[k],s[a]),!!g}function e(a,b){var c,e,f;for(c=0;c0)return!0;return!1}function g(a,c){var e,f,g,h,i;for(e=0;e0)return!0;return!1}for(var h,i,j,k,l,m,n,o,p,q,r,s=a.concat(),t=[],u=[],v=0,w=b.length;w>v;v++)t.push(v);for(var x=2*t.length;t.length>0;){if(x--,0>x){console.log("Infinite Loop! Holes left:"+t.length+", Probably Hole outside Shape!");break}for(j=0;j=0)break;u[n]=!0}if(i>=0)break}}return s}for(var h,i,j,k,l,m,n={},o=a.concat(),p=0,q=b.length;q>p;p++)Array.prototype.push.apply(o,b[p]);for(h=0,i=o.length;i>h;h++)l=o[h].x+":"+o[h].y,void 0!==n[l]&&console.log("Duplicate point",l),n[l]=h;var r=g(a,b),s=e.FontUtils.Triangulate(r,!1);for(h=0,i=s.length;i>h;h++)for(k=s[h],j=0;3>j;j++)l=k[j].x+":"+k[j].y,m=n[l],void 0!==m&&(k[j]=m);return s.concat()},isClockWise:function(a){return e.FontUtils.Triangulate.area(a)<0},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){var c=1-a;return 3*c*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a,b)+this.b3p1(a,c)+this.b3p2(a,d)+this.b3p3(a,e)}},e.LineCurve=function(a,b){this.v1=a,this.v2=b},e.LineCurve.prototype=Object.create(e.Curve.prototype),e.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);return b.multiplyScalar(a).add(this.v1),b},e.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)},e.LineCurve.prototype.getTangent=function(a){var b=this.v2.clone().sub(this.v1);return b.normalize()},e.QuadraticBezierCurve=function(a,b,c){this.v0=a,this.v1=b,this.v2=c},e.QuadraticBezierCurve.prototype=Object.create(e.Curve.prototype),e.QuadraticBezierCurve.prototype.getPoint=function(a){var b,c;return b=e.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x),c=e.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y),new e.Vector2(b,c)},e.QuadraticBezierCurve.prototype.getTangent=function(a){var b,c;b=e.Curve.Utils.tangentQuadraticBezier(a,this.v0.x,this.v1.x,this.v2.x),c=e.Curve.Utils.tangentQuadraticBezier(a,this.v0.y,this.v1.y,this.v2.y);var d=new e.Vector2(b,c);return d.normalize(),d},e.CubicBezierCurve=function(a,b,c,d){this.v0=a,this.v1=b,this.v2=c,this.v3=d},e.CubicBezierCurve.prototype=Object.create(e.Curve.prototype),e.CubicBezierCurve.prototype.getPoint=function(a){var b,c;return b=e.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),c=e.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y),new e.Vector2(b,c)},e.CubicBezierCurve.prototype.getTangent=function(a){var b,c;b=e.Curve.Utils.tangentCubicBezier(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),c=e.Curve.Utils.tangentCubicBezier(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);var d=new e.Vector2(b,c);return d.normalize(),d},e.SplineCurve=function(a){this.points=void 0==a?[]:a},e.SplineCurve.prototype=Object.create(e.Curve.prototype),e.SplineCurve.prototype.getPoint=function(a){var b,c,d,f=new e.Vector2,g=[],h=this.points;return b=(h.length-1)*a,c=Math.floor(b),d=b-c,g[0]=0==c?c:c-1,g[1]=c,g[2]=c>h.length-2?h.length-1:c+1,g[3]=c>h.length-3?h.length-1:c+2,f.x=e.Curve.Utils.interpolate(h[g[0]].x,h[g[1]].x,h[g[2]].x,h[g[3]].x,d),f.y=e.Curve.Utils.interpolate(h[g[0]].y,h[g[1]].y,h[g[2]].y,h[g[3]].y,d),f},e.EllipseCurve=function(a,b,c,d,e,f,g){this.aX=a,this.aY=b,this.xRadius=c,this.yRadius=d,this.aStartAngle=e,this.aEndAngle=f,this.aClockwise=g},e.EllipseCurve.prototype=Object.create(e.Curve.prototype),e.EllipseCurve.prototype.getPoint=function(a){var b,c=this.aEndAngle-this.aStartAngle;0>c&&(c+=2*Math.PI),c>2*Math.PI&&(c-=2*Math.PI),b=this.aClockwise===!0?this.aEndAngle+(1-a)*(2*Math.PI-c):this.aStartAngle+a*c;var d=this.aX+this.xRadius*Math.cos(b),f=this.aY+this.yRadius*Math.sin(b);return new e.Vector2(d,f)},e.ArcCurve=function(a,b,c,d,f,g){e.EllipseCurve.call(this,a,b,c,c,d,f,g)},e.ArcCurve.prototype=Object.create(e.EllipseCurve.prototype),e.LineCurve3=e.Curve.create(function(a,b){this.v1=a,this.v2=b},function(a){var b=new e.Vector3;return b.subVectors(this.v2,this.v1),b.multiplyScalar(a),b.add(this.v1),b}),e.QuadraticBezierCurve3=e.Curve.create(function(a,b,c){this.v0=a,this.v1=b,this.v2=c},function(a){var b,c,d;return b=e.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x),c=e.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y),d=e.Shape.Utils.b2(a,this.v0.z,this.v1.z,this.v2.z),new e.Vector3(b,c,d)}),e.CubicBezierCurve3=e.Curve.create(function(a,b,c,d){this.v0=a,this.v1=b,this.v2=c,this.v3=d},function(a){var b,c,d;return b=e.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),c=e.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y),d=e.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z),new e.Vector3(b,c,d)}),e.SplineCurve3=e.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b,c,d,f=new e.Vector3,g=[],h=this.points;b=(h.length-1)*a,c=Math.floor(b),d=b-c,g[0]=0==c?c:c-1,g[1]=c,g[2]=c>h.length-2?h.length-1:c+1,g[3]=c>h.length-3?h.length-1:c+2;var i=h[g[0]],j=h[g[1]],k=h[g[2]],l=h[g[3]];return f.x=e.Curve.Utils.interpolate(i.x,j.x,k.x,l.x,d),f.y=e.Curve.Utils.interpolate(i.y,j.y,k.y,l.y,d),f.z=e.Curve.Utils.interpolate(i.z,j.z,k.z,l.z,d),f}),e.ClosedSplineCurve3=e.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b,c,d,f=new e.Vector3,g=[],h=this.points;return b=(h.length-0)*a,c=Math.floor(b),d=b-c,c+=c>0?0:(Math.floor(Math.abs(c)/h.length)+1)*h.length,g[0]=(c-1)%h.length,g[1]=c%h.length,g[2]=(c+1)%h.length,g[3]=(c+2)%h.length,f.x=e.Curve.Utils.interpolate(h[g[0]].x,h[g[1]].x,h[g[2]].x,h[g[3]].x,d),f.y=e.Curve.Utils.interpolate(h[g[0]].y,h[g[1]].y,h[g[2]].y,h[g[3]].y,d),f.z=e.Curve.Utils.interpolate(h[g[0]].z,h[g[1]].z,h[g[2]].z,h[g[3]].z,d),f}),e.AnimationHandler=function(){var a=[],b={},c={};c.update=function(b){for(var c=0;ca;a++){var c=this.hierarchy[a];c.matrixAutoUpdate=!0,void 0===c.animationCache&&(c.animationCache={},c.animationCache.prevKey={pos:0,rot:0,scl:0},c.animationCache.nextKey={pos:0,rot:0,scl:0},c.animationCache.originalMatrix=c instanceof e.Bone?c.skinMatrix:c.matrix);var d=c.animationCache.prevKey,f=c.animationCache.nextKey;d.pos=this.data.hierarchy[a].keys[0],d.rot=this.data.hierarchy[a].keys[0],d.scl=this.data.hierarchy[a].keys[0],f.pos=this.getNextKeyWith("pos",a,1),f.rot=this.getNextKeyWith("rot",a,1),f.scl=this.getNextKeyWith("scl",a,1)}},e.Animation.prototype.update=function(){var a=[],b=new e.Vector3,c=function(a,b){var c,e,f,g,h,i,j,k,l,m=[],n=[];return c=(a.length-1)*b,e=Math.floor(c),f=c-e,m[0]=0===e?e:e-1,m[1]=e,m[2]=e>a.length-2?e:e+1,m[3]=e>a.length-3?e:e+2,i=a[m[0]],j=a[m[1]],k=a[m[2]],l=a[m[3]],g=f*f,h=f*g,n[0]=d(i[0],j[0],k[0],l[0],f,g,h),n[1]=d(i[1],j[1],k[1],l[1],f,g,h),n[2]=d(i[2],j[2],k[2],l[2],f,g,h),n},d=function(a,b,c,d,e,f,g){var h=.5*(c-a),i=.5*(d-b);return(2*(b-c)+h+i)*g+(-3*(b-c)-2*h-i)*f+h*e+b};return function(d){if(this.isPlaying!==!1){this.currentTime+=d*this.timeScale;var f,g=["pos","rot","scl"],h=this.data.length;if(this.loop===!0&&this.currentTime>h)this.currentTime%=h,this.reset();else if(this.loop===!1&&this.currentTime>h)return void this.stop();this.currentTime=Math.min(this.currentTime,h);for(var i=0,j=this.hierarchy.length;j>i;i++)for(var k=this.hierarchy[i],l=k.animationCache,m=0;3>m;m++){var n=g[m],o=l.prevKey[n],p=l.nextKey[n];if(p.time<=this.currentTime){for(o=this.data.hierarchy[i].keys[0],p=this.getNextKeyWith(n,i,1);p.timeo.index;)o=p,p=this.getNextKeyWith(n,i,p.index+1);l.prevKey[n]=o,l.nextKey[n]=p}k.matrixAutoUpdate=!0,k.matrixWorldNeedsUpdate=!0;var q=(this.currentTime-o.time)/(p.time-o.time),r=o[n],s=p[n];if(0>q&&(q=0),q>1&&(q=1),"pos"===n){if(f=k.position,this.interpolationType===e.AnimationHandler.LINEAR)f.x=r[0]+(s[0]-r[0])*q,f.y=r[1]+(s[1]-r[1])*q,f.z=r[2]+(s[2]-r[2])*q;else if(this.interpolationType===e.AnimationHandler.CATMULLROM||this.interpolationType===e.AnimationHandler.CATMULLROM_FORWARD){a[0]=this.getPrevKeyWith("pos",i,o.index-1).pos,a[1]=r,a[2]=s,a[3]=this.getNextKeyWith("pos",i,p.index+1).pos,q=.33*q+.33;var t=c(a,q);if(f.x=t[0],f.y=t[1],f.z=t[2],this.interpolationType===e.AnimationHandler.CATMULLROM_FORWARD){var u=c(a,1.01*q);b.set(u[0],u[1],u[2]),b.sub(f),b.y=0,b.normalize();var v=Math.atan2(b.x,b.z);k.rotation.set(0,v,0)}}}else"rot"===n?e.Quaternion.slerp(r,s,k.quaternion,q):"scl"===n&&(f=k.scale,f.x=r[0]+(s[0]-r[0])*q,f.y=r[1]+(s[1]-r[1])*q,f.z=r[2]+(s[2]-r[2])*q)}}}}(),e.Animation.prototype.getNextKeyWith=function(a,b,c){var d=this.data.hierarchy[b].keys;for(this.interpolationType===e.AnimationHandler.CATMULLROM||this.interpolationType===e.AnimationHandler.CATMULLROM_FORWARD?c=c0?c:0:c>=0?c:c+d.length;c>=0;c--)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[d.length-1]},e.KeyFrameAnimation=function(a,b){this.root=a,this.data=e.AnimationHandler.get(b),this.hierarchy=e.AnimationHandler.parse(a),this.currentTime=0,this.timeScale=.001,this.isPlaying=!1,this.isPaused=!0,this.loop=!0;for(var c=0,d=this.hierarchy.length;d>c;c++){var f=this.data.hierarchy[c].keys,g=this.data.hierarchy[c].sids,h=this.hierarchy[c];if(f.length&&g){for(var i=0;ib;b++){c=this.hierarchy[b],d=this.data.hierarchy[b],void 0===d.animationCache&&(d.animationCache={},d.animationCache.prevKey=null,d.animationCache.nextKey=null,d.animationCache.originalMatrix=c instanceof e.Bone?c.skinMatrix:c.matrix);var g=this.data.hierarchy[b].keys;g.length&&(d.animationCache.prevKey=g[0],d.animationCache.nextKey=g[1],this.startTime=Math.min(g[0].time,this.startTime),this.endTime=Math.max(g[g.length-1].time,this.endTime))}this.update(0)}this.isPaused=!1,e.AnimationHandler.addToUpdate(this)},e.KeyFrameAnimation.prototype.pause=function(){this.isPaused?e.AnimationHandler.addToUpdate(this):e.AnimationHandler.removeFromUpdate(this),this.isPaused=!this.isPaused},e.KeyFrameAnimation.prototype.stop=function(){this.isPlaying=!1,this.isPaused=!1,e.AnimationHandler.removeFromUpdate(this);for(var a=0;ab&&(this.currentTime%=b),this.currentTime=Math.min(this.currentTime,b);for(var c=0,d=this.hierarchy.length;d>c;c++){var e=this.hierarchy[c],f=this.data.hierarchy[c],g=f.keys,h=f.animationCache;if(g.length){var i=h.prevKey,j=h.nextKey;if(j.time<=this.currentTime){for(;j.timei.index;)i=j,j=g[i.index+1];h.prevKey=i,h.nextKey=j}j.time>=this.currentTime?i.interpolate(j,this.currentTime):i.interpolate(j,j.time),this.data.hierarchy[c].node.updateMatrix(),e.matrixWorldNeedsUpdate=!0}}}},e.KeyFrameAnimation.prototype.getNextKeyWith=function(a,b,c){var d=this.data.hierarchy[b].keys;for(c%=d.length;c=0?c:c+d.length;c>=0;c--)if(d[c].hasTarget(a))return d[c];return d[d.length-1]},e.MorphAnimation=function(a){this.mesh=a,this.frames=a.morphTargetInfluences.length,this.currentTime=0,this.duration=1e3,this.loop=!0,this.isPlaying=!1},e.MorphAnimation.prototype={play:function(){this.isPlaying=!0},pause:function(){this.isPlaying=!1},update:function(){var a=0,b=0;return function(c){if(this.isPlaying!==!1){this.currentTime+=c,this.loop===!0&&this.currentTime>this.duration&&(this.currentTime%=this.duration),this.currentTime=Math.min(this.currentTime,this.duration);var d=this.duration/this.frames,e=Math.floor(this.currentTime/d);e!=b&&(this.mesh.morphTargetInfluences[a]=0,this.mesh.morphTargetInfluences[b]=1,this.mesh.morphTargetInfluences[e]=0,a=b,b=e),this.mesh.morphTargetInfluences[e]=this.currentTime%d/d,this.mesh.morphTargetInfluences[a]=1-this.mesh.morphTargetInfluences[e]}}}()},e.CubeCamera=function(a,b,c){e.Object3D.call(this),this.className="CubeCamera";var d=90,f=1,g=new e.PerspectiveCamera(d,f,a,b);g.up.set(0,-1,0),g.lookAt(new e.Vector3(1,0,0)),this.add(g);var h=new e.PerspectiveCamera(d,f,a,b);h.up.set(0,-1,0),h.lookAt(new e.Vector3(-1,0,0)),this.add(h);var i=new e.PerspectiveCamera(d,f,a,b);i.up.set(0,0,1),i.lookAt(new e.Vector3(0,1,0)),this.add(i);var j=new e.PerspectiveCamera(d,f,a,b);j.up.set(0,0,-1),j.lookAt(new e.Vector3(0,-1,0)),this.add(j);var k=new e.PerspectiveCamera(d,f,a,b);k.up.set(0,-1,0),k.lookAt(new e.Vector3(0,0,1)),this.add(k);var l=new e.PerspectiveCamera(d,f,a,b);l.up.set(0,-1,0),l.lookAt(new e.Vector3(0,0,-1)),this.add(l),this.renderTarget=new e.WebGLRenderTargetCube(c,c,{format:e.RGBFormat,magFilter:e.LinearFilter,minFilter:e.LinearFilter}),this.updateCubeMap=function(a,b){var c=this.renderTarget,d=c.generateMipmaps;c.generateMipmaps=!1,c.activeCubeFace=0,a.render(b,g,c),c.activeCubeFace=1,a.render(b,h,c),c.activeCubeFace=2,a.render(b,i,c),c.activeCubeFace=3,a.render(b,j,c),c.activeCubeFace=4,a.render(b,k,c),c.generateMipmaps=d,c.activeCubeFace=5,a.render(b,l,c)}},e.CubeCamera.prototype=Object.create(e.Object3D.prototype),e.CombinedCamera=function(a,b,c,d,f,g,h){e.Camera.call(this),this.className="CombinedCamera",this.fov=c,this.left=-a/2,this.right=a/2,this.top=b/2,this.bottom=-b/2,this.cameraO=new e.OrthographicCamera(a/-2,a/2,b/2,b/-2,g,h),this.cameraP=new e.PerspectiveCamera(c,a/b,d,f),this.zoom=1,this.toPerspective()},e.CombinedCamera.prototype=Object.create(e.Camera.prototype),e.CombinedCamera.prototype.toPerspective=function(){this.near=this.cameraP.near,this.far=this.cameraP.far,this.cameraP.fov=this.fov/this.zoom,this.cameraP.updateProjectionMatrix(),this.projectionMatrix=this.cameraP.projectionMatrix,this.inPerspectiveMode=!0,this.inOrthographicMode=!1},e.CombinedCamera.prototype.toOrthographic=function(){var a=this.fov,b=this.cameraP.aspect,c=this.cameraP.near,d=this.cameraP.far,e=(c+d)/2,f=Math.tan(a/2)*e,g=2*f,h=g*b,i=h/2;f/=this.zoom,i/=this.zoom,this.cameraO.left=-i,this.cameraO.right=i,this.cameraO.top=f,this.cameraO.bottom=-f,this.cameraO.updateProjectionMatrix(),this.near=this.cameraO.near,this.far=this.cameraO.far,this.projectionMatrix=this.cameraO.projectionMatrix,this.inPerspectiveMode=!1,this.inOrthographicMode=!0},e.CombinedCamera.prototype.setSize=function(a,b){this.cameraP.aspect=a/b,this.left=-a/2,this.right=a/2,this.top=b/2,this.bottom=-b/2},e.CombinedCamera.prototype.setFov=function(a){this.fov=a,this.inPerspectiveMode?this.toPerspective():this.toOrthographic()},e.CombinedCamera.prototype.updateProjectionMatrix=function(){this.inPerspectiveMode?this.toPerspective():(this.toPerspective(),this.toOrthographic())},e.CombinedCamera.prototype.setLens=function(a,b){void 0===b&&(b=24);var c=2*e.Math.radToDeg(Math.atan(b/(2*a)));return this.setFov(c),c},e.CombinedCamera.prototype.setZoom=function(a){this.zoom=a,this.inPerspectiveMode?this.toPerspective():this.toOrthographic()},e.CombinedCamera.prototype.toFrontView=function(){this.rotation.x=0,this.rotation.y=0,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toBackView=function(){this.rotation.x=0,this.rotation.y=Math.PI,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toLeftView=function(){this.rotation.x=0,this.rotation.y=-Math.PI/2,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toRightView=function(){this.rotation.x=0,this.rotation.y=Math.PI/2,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toTopView=function(){this.rotation.x=-Math.PI/2,this.rotation.y=0,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toBottomView=function(){this.rotation.x=Math.PI/2,this.rotation.y=0,this.rotation.z=0,this.rotationAutoUpdate=!1},e.BoxGeometry=function(a,b,c,d,f,g){function h(a,b,c,d,f,g,h,j){var k,l,m,n=i.widthSegments,o=i.heightSegments,p=f/2,q=g/2,r=i.vertices.length;"x"===a&&"y"===b||"y"===a&&"x"===b?k="z":"x"===a&&"z"===b||"z"===a&&"x"===b?(k="y",o=i.depthSegments):("z"===a&&"y"===b||"y"===a&&"z"===b)&&(k="x",n=i.depthSegments);var s=n+1,t=o+1,u=f/n,v=g/o,w=new e.Vector3;for(w[k]=h>0?1:-1,m=0;t>m;m++)for(l=0;s>l;l++){var x=new e.Vector3;x[a]=(l*u-p)*c,x[b]=(m*v-q)*d,x[k]=h,i.vertices.push(x)}for(m=0;o>m;m++)for(l=0;n>l;l++){var y=l+s*m,z=l+s*(m+1),A=l+1+s*(m+1),B=l+1+s*m,C=new e.Vector2(l/n,1-m/o),D=new e.Vector2(l/n,1-(m+1)/o),E=new e.Vector2((l+1)/n,1-(m+1)/o),F=new e.Vector2((l+1)/n,1-m/o),G=new e.Face3(y+r,z+r,B+r);G.normal.copy(w),G.vertexNormals.push(w.clone(),w.clone(),w.clone()),G.materialIndex=j,i.faces.push(G),i.faceVertexUvs[0].push([C,D,F]),G=new e.Face3(z+r,A+r,B+r),G.normal.copy(w),G.vertexNormals.push(w.clone(),w.clone(),w.clone()),G.materialIndex=j,i.faces.push(G),i.faceVertexUvs[0].push([D.clone(),E,F.clone()])}}e.Geometry.call(this),this.className="BoxGeometry";var i=this;this.width=a,this.height=b,this.depth=c,this.widthSegments=d||1,this.heightSegments=f||1,this.depthSegments=g||1;var j=this.width/2,k=this.height/2,l=this.depth/2;h("z","y",-1,-1,this.depth,this.height,j,0),h("z","y",1,-1,this.depth,this.height,-j,1),h("x","z",1,1,this.width,this.depth,k,2),h("x","z",1,-1,this.width,this.depth,-k,3),h("x","y",1,-1,this.width,this.height,l,4),h("x","y",-1,-1,this.width,this.height,-l,5),this.computeCentroids(),this.mergeVertices()},e.BoxGeometry.prototype=Object.create(e.Geometry.prototype),e.CircleGeometry=function(a,b,c,d){e.Geometry.call(this),this.className="CircleGeometry",this.radius=a=a||50,this.segments=b=void 0!==b?Math.max(3,b):8,this.thetaStart=c=void 0!==c?c:0,this.thetaLength=d=void 0!==d?d:2*Math.PI;var f,g=[],h=new e.Vector3,i=new e.Vector2(.5,.5);for(this.vertices.push(h),g.push(i),f=0;b>=f;f++){var j=new e.Vector3,k=c+f/b*d;j.x=a*Math.cos(k),j.y=a*Math.sin(k),this.vertices.push(j),g.push(new e.Vector2((j.x/a+1)/2,(j.y/a+1)/2))}var l=new e.Vector3(0,0,1);for(f=1;b>=f;f++){var m=f,n=f+1,o=0;this.faces.push(new e.Face3(m,n,o,[l.clone(),l.clone(),l.clone()])),this.faceVertexUvs[0].push([g[f].clone(),g[f+1].clone(),i.clone()])}this.computeCentroids(),this.computeFaceNormals(),this.boundingSphere=new e.Sphere(new e.Vector3,a)},e.CircleGeometry.prototype=Object.create(e.Geometry.prototype),e.CubeGeometry=e.BoxGeometry,e.CylinderGeometry=function(a,b,c,d,f,g){e.Geometry.call(this),this.className="CylinderGeometry",this.radiusTop=a=void 0!==a?a:20,this.radiusBottom=b=void 0!==b?b:20,this.height=c=void 0!==c?c:100,this.radialSegments=d=d||8,this.heightSegments=f=f||1,this.openEnded=g=void 0!==g?g:!1;var h,i,j=c/2,k=[],l=[];for(i=0;f>=i;i++){var m=[],n=[],o=i/f,p=o*(b-a)+a;for(h=0;d>=h;h++){var q=h/d,r=new e.Vector3;r.x=p*Math.sin(q*Math.PI*2),r.y=-o*c+j,r.z=p*Math.cos(q*Math.PI*2),this.vertices.push(r),m.push(this.vertices.length-1),n.push(new e.Vector2(q,1-o))}k.push(m),l.push(n)}var s,t,u=(b-a)/c;for(h=0;d>h;h++)for(0!==a?(s=this.vertices[k[0][h]].clone(),t=this.vertices[k[0][h+1]].clone()):(s=this.vertices[k[1][h]].clone(),t=this.vertices[k[1][h+1]].clone()),s.setY(Math.sqrt(s.x*s.x+s.z*s.z)*u).normalize(),t.setY(Math.sqrt(t.x*t.x+t.z*t.z)*u).normalize(),i=0;f>i;i++){var v=k[i][h],w=k[i+1][h],x=k[i+1][h+1],y=k[i][h+1],z=s.clone(),A=s.clone(),B=t.clone(),C=t.clone(),D=l[i][h].clone(),E=l[i+1][h].clone(),F=l[i+1][h+1].clone(),G=l[i][h+1].clone();this.faces.push(new e.Face3(v,w,y,[z,A,C])),this.faceVertexUvs[0].push([D,E,G]),this.faces.push(new e.Face3(w,x,y,[A.clone(),B,C.clone()])),this.faceVertexUvs[0].push([E.clone(),F,G.clone()])}if(g===!1&&a>0)for(this.vertices.push(new e.Vector3(0,j,0)),h=0;d>h;h++){var v=k[0][h],w=k[0][h+1],x=this.vertices.length-1,z=new e.Vector3(0,1,0),A=new e.Vector3(0,1,0),B=new e.Vector3(0,1,0),D=l[0][h].clone(),E=l[0][h+1].clone(),F=new e.Vector2(E.x,0);this.faces.push(new e.Face3(v,w,x,[z,A,B])),this.faceVertexUvs[0].push([D,E,F])}if(g===!1&&b>0)for(this.vertices.push(new e.Vector3(0,-j,0)),h=0;d>h;h++){var v=k[i][h+1],w=k[i][h],x=this.vertices.length-1,z=new e.Vector3(0,-1,0),A=new e.Vector3(0,-1,0),B=new e.Vector3(0,-1,0),D=l[i][h+1].clone(),E=l[i][h].clone(),F=new e.Vector2(E.x,1);this.faces.push(new e.Face3(v,w,x,[z,A,B])),this.faceVertexUvs[0].push([D,E,F])}this.computeCentroids(),this.computeFaceNormals()},e.CylinderGeometry.prototype=Object.create(e.Geometry.prototype),e.ExtrudeGeometry=function(a,b){return"undefined"==typeof a?void(a=[]):(e.Geometry.call(this),this.className="ExtrudeGeometry",a=a instanceof Array?a:[a],this.shapebb=a[a.length-1].getBoundingBox(),this.addShapeList(a,b),this.computeCentroids(),void this.computeFaceNormals())},e.ExtrudeGeometry.prototype=Object.create(e.Geometry.prototype),e.ExtrudeGeometry.prototype.addShapeList=function(a,b){for(var c=a.length,d=0;c>d;d++){var e=a[d];this.addShape(e,b)}},e.ExtrudeGeometry.prototype.addShape=function(a,b){function c(a,b,c){return b?b.clone().multiplyScalar(c).add(a):e.onerror("die, vec not specified")}function d(a,b,c){var d,f,g=1e-10,h=e.Math.sign,i=1,j=a.x-b.x,k=a.y-b.y,l=c.x-a.x,m=c.y-a.y,n=j*j+k*k,o=j*m-k*l;if(Math.abs(o)>g){var p=Math.sqrt(n),q=Math.sqrt(l*l+m*m),r=b.x-k/p,s=b.y+j/p,t=c.x-m/q,u=c.y+l/q,v=((t-r)*m-(u-s)*l)/(j*m-k*l);d=r+j*v-a.x,f=s+k*v-a.y;var w=d*d+f*f;if(2>=w)return new e.Vector2(d,f);i=Math.sqrt(w/2)}else{var x=!1;j>g?l>g&&(x=!0):-g>j?-g>l&&(x=!0):h(k)==h(m)&&(x=!0),x?(d=-k,f=j,i=Math.sqrt(n)):(d=j,f=k,i=Math.sqrt(n/2))}return new e.Vector2(d/i,f/i)}function f(){if(u){var a=0,b=T*a;for(W=0;U>W;W++)S=L[W],j(S[2]+b,S[1]+b,S[0]+b,!0);for(a=w+2*t,b=T*a,W=0;U>W;W++)S=L[W],j(S[0]+b,S[1]+b,S[2]+b,!1)}else{for(W=0;U>W;W++)S=L[W],j(S[2],S[1],S[0],!0);for(W=0;U>W;W++)S=L[W],j(S[0]+T*w,S[1]+T*w,S[2]+T*w,!1)}}function g(){var a=0;for(h(M,a),a+=M.length,D=0,E=J.length;E>D;D++)C=J[D],h(C,a),a+=C.length}function h(a,b){var c,d;for(W=a.length;--W>=0;){c=W,d=W-1,0>d&&(d=a.length-1);var e=0,f=w+2*t;for(e=0;f>e;e++){var g=T*e,h=T*(e+1),i=b+c+g,j=b+d+g,l=b+d+h,m=b+c+h;k(i,j,l,m,a,e,f,c,d)}}}function i(a,b,c){F.vertices.push(new e.Vector3(a,b,c))}function j(c,d,f,g){c+=G,d+=G,f+=G,F.faces.push(new e.Face3(c,d,f,null,null,z));var h=g?B.generateBottomUV(F,a,b,c,d,f):B.generateTopUV(F,a,b,c,d,f);F.faceVertexUvs[0].push(h)}function k(c,d,f,g,h,i,j,k,l){c+=G,d+=G,f+=G,g+=G,F.faces.push(new e.Face3(c,d,g,null,null,A)),F.faces.push(new e.Face3(d,f,g,null,null,A));var m=B.generateSideWallUV(F,a,h,b,c,d,f,g,i,j,k,l);F.faceVertexUvs[0].push([m[0],m[1],m[3]]),F.faceVertexUvs[0].push([m[1],m[2],m[3]])}var l,m,n,o,p,q=void 0!==b.amount?b.amount:100,r=void 0!==b.bevelThickness?b.bevelThickness:6,s=void 0!==b.bevelSize?b.bevelSize:r-2,t=void 0!==b.bevelSegments?b.bevelSegments:3,u=void 0!==b.bevelEnabled?b.bevelEnabled:!0,v=void 0!==b.curveSegments?b.curveSegments:12,w=void 0!==b.steps?b.steps:1,x=b.extrudePath,y=!1,z=b.material,A=b.extrudeMaterial,B=void 0!==b.UVGenerator?b.UVGenerator:e.ExtrudeGeometry.WorldUVGenerator;this.shapebb;x&&(l=x.getSpacedPoints(w),y=!0,u=!1,m=void 0!==b.frames?b.frames:new e.TubeGeometry.FrenetFrames(x,w,!1),n=new e.Vector3,o=new e.Vector3,p=new e.Vector3),u||(t=0,r=0,s=0);var C,D,E,F=this,G=this.vertices.length,H=a.extractPoints(v),I=H.shape,J=H.holes,K=!e.Shape.Utils.isClockWise(I);if(K){for(I=I.reverse(),D=0,E=J.length;E>D;D++)C=J[D],e.Shape.Utils.isClockWise(C)&&(J[D]=C.reverse());K=!1}var L=e.Shape.Utils.triangulateShape(I,J),M=I;for(D=0,E=J.length;E>D;D++)C=J[D],I=I.concat(C);for(var N,O,P,Q,R,S,T=I.length,U=L.length,V=(M.length,180/Math.PI,[]),W=0,X=M.length,Y=X-1,Z=W+1;X>W;W++,Y++,Z++){Y===X&&(Y=0),Z===X&&(Z=0);M[W],M[Y],M[Z];V[W]=d(M[W],M[Y],M[Z])}var $,_=[],aa=V.concat();for(D=0,E=J.length;E>D;D++){for(C=J[D],$=[],W=0,X=C.length,Y=X-1,Z=W+1;X>W;W++,Y++,Z++)Y===X&&(Y=0),Z===X&&(Z=0),$[W]=d(C[W],C[Y],C[Z]);_.push($),aa=aa.concat($)}for(N=0;t>N;N++){for(P=N/t,Q=r*(1-P),O=s*Math.sin(P*Math.PI/2),W=0,X=M.length;X>W;W++)R=c(M[W],V[W],O),i(R.x,R.y,-Q);for(D=0,E=J.length;E>D;D++)for(C=J[D],$=_[D],W=0,X=C.length;X>W;W++)R=c(C[W],$[W],O),i(R.x,R.y,-Q)}for(O=s,W=0;T>W;W++)R=u?c(I[W],aa[W],O):I[W],y?(o.copy(m.normals[0]).multiplyScalar(R.x),n.copy(m.binormals[0]).multiplyScalar(R.y),p.copy(l[0]).add(o).add(n),i(p.x,p.y,p.z)):i(R.x,R.y,0);var ba;for(ba=1;w>=ba;ba++)for(W=0;T>W;W++)R=u?c(I[W],aa[W],O):I[W],y?(o.copy(m.normals[ba]).multiplyScalar(R.x),n.copy(m.binormals[ba]).multiplyScalar(R.y),p.copy(l[ba]).add(o).add(n),i(p.x,p.y,p.z)):i(R.x,R.y,q/w*ba);for(N=t-1;N>=0;N--){for(P=N/t,Q=r*(1-P),O=s*Math.sin(P*Math.PI/2),W=0,X=M.length;X>W;W++)R=c(M[W],V[W],O),i(R.x,R.y,q+Q);for(D=0,E=J.length;E>D;D++)for(C=J[D],$=_[D],W=0,X=C.length;X>W;W++)R=c(C[W],$[W],O),y?i(R.x,R.y+l[w-1].y,l[w-1].x+Q):i(R.x,R.y,q+Q)}f(),g()},e.ExtrudeGeometry.WorldUVGenerator={generateTopUV:function(a,b,c,d,f,g){var h=a.vertices[d].x,i=a.vertices[d].y,j=a.vertices[f].x,k=a.vertices[f].y,l=a.vertices[g].x,m=a.vertices[g].y; +return[new e.Vector2(h,i),new e.Vector2(j,k),new e.Vector2(l,m)]},generateBottomUV:function(a,b,c,d,e,f){return this.generateTopUV(a,b,c,d,e,f)},generateSideWallUV:function(a,b,c,d,f,g,h,i,j,k,l,m){var n=a.vertices[f].x,o=a.vertices[f].y,p=a.vertices[f].z,q=a.vertices[g].x,r=a.vertices[g].y,s=a.vertices[g].z,t=a.vertices[h].x,u=a.vertices[h].y,v=a.vertices[h].z,w=a.vertices[i].x,x=a.vertices[i].y,y=a.vertices[i].z;return Math.abs(o-r)<.01?[new e.Vector2(n,1-p),new e.Vector2(q,1-s),new e.Vector2(t,1-v),new e.Vector2(w,1-y)]:[new e.Vector2(o,1-p),new e.Vector2(r,1-s),new e.Vector2(u,1-v),new e.Vector2(x,1-y)]}},e.ExtrudeGeometry.__v1=new e.Vector2,e.ExtrudeGeometry.__v2=new e.Vector2,e.ExtrudeGeometry.__v3=new e.Vector2,e.ExtrudeGeometry.__v4=new e.Vector2,e.ExtrudeGeometry.__v5=new e.Vector2,e.ExtrudeGeometry.__v6=new e.Vector2,e.ShapeGeometry=function(a,b){e.Geometry.call(this),this.className="ShapeGeometry",a instanceof Array==!1&&(a=[a]),this.shapebb=a[a.length-1].getBoundingBox(),this.addShapeList(a,b),this.computeCentroids(),this.computeFaceNormals()},e.ShapeGeometry.prototype=Object.create(e.Geometry.prototype),e.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;d>c;c++)this.addShape(a[c],b);return this},e.ShapeGeometry.prototype.addShape=function(a,b){void 0===b&&(b={});var c,d,f,g=void 0!==b.curveSegments?b.curveSegments:12,h=b.material,i=void 0===b.UVGenerator?e.ExtrudeGeometry.WorldUVGenerator:b.UVGenerator,j=(this.shapebb,this.vertices.length),k=a.extractPoints(g),l=k.shape,m=k.holes,n=!e.Shape.Utils.isClockWise(l);if(n){for(l=l.reverse(),c=0,d=m.length;d>c;c++)f=m[c],e.Shape.Utils.isClockWise(f)&&(m[c]=f.reverse());n=!1}var o=e.Shape.Utils.triangulateShape(l,m),p=l;for(c=0,d=m.length;d>c;c++)f=m[c],l=l.concat(f);var q,r,s=l.length,t=o.length;p.length;for(c=0;s>c;c++)q=l[c],this.vertices.push(new e.Vector3(q.x,q.y,0));for(c=0;t>c;c++){r=o[c];var u=r[0]+j,v=r[1]+j,w=r[2]+j;this.faces.push(new e.Face3(u,v,w,null,null,h)),this.faceVertexUvs[0].push(i.generateBottomUV(this,a,b,u,v,w))}},e.LatheGeometry=function(a,b,c,d){e.Geometry.call(this),this.className="LatheGeometry",b=b||12,c=c||0,d=d||2*Math.PI;for(var f=1/(a.length-1),g=1/b,h=0,i=b;i>=h;h++)for(var j=c+h*g*d,k=Math.cos(j),l=Math.sin(j),m=0,n=a.length;n>m;m++){var o=a[m],p=new e.Vector3;p.x=k*o.x-l*o.y,p.y=l*o.x+k*o.y,p.z=o.z,this.vertices.push(p)}for(var q=a.length,h=0,i=b;i>h;h++)for(var m=0,n=a.length-1;n>m;m++){var r=m+q*h,s=r,t=r+q,k=r+1+q,u=r+1,v=h*g,w=m*f,x=v+g,y=w+f;this.faces.push(new e.Face3(s,t,u)),this.faceVertexUvs[0].push([new e.Vector2(v,w),new e.Vector2(x,w),new e.Vector2(v,y)]),this.faces.push(new e.Face3(t,k,u)),this.faceVertexUvs[0].push([new e.Vector2(x,w),new e.Vector2(x,y),new e.Vector2(v,y)])}this.mergeVertices(),this.computeCentroids(),this.computeFaceNormals(),this.computeVertexNormals()},e.LatheGeometry.prototype=Object.create(e.Geometry.prototype),e.PlaneGeometry=function(a,b,c,d){e.Geometry.call(this),this.className="PlaneGeometry",this.width=a,this.height=b,this.widthSegments=c||1,this.heightSegments=d||1;var f,g,h=a/2,i=b/2,j=this.widthSegments,k=this.heightSegments,l=j+1,m=k+1,n=this.width/j,o=this.height/k,p=new e.Vector3(0,0,1);for(g=0;m>g;g++)for(f=0;l>f;f++){var q=f*n-h,r=g*o-i;this.vertices.push(new e.Vector3(q,-r,0))}for(g=0;k>g;g++)for(f=0;j>f;f++){var s=f+l*g,t=f+l*(g+1),u=f+1+l*(g+1),v=f+1+l*g,w=new e.Vector2(f/j,1-g/k),x=new e.Vector2(f/j,1-(g+1)/k),y=new e.Vector2((f+1)/j,1-(g+1)/k),z=new e.Vector2((f+1)/j,1-g/k),A=new e.Face3(s,t,v);A.normal.copy(p),A.vertexNormals.push(p.clone(),p.clone(),p.clone()),this.faces.push(A),this.faceVertexUvs[0].push([w,x,z]),A=new e.Face3(t,u,v),A.normal.copy(p),A.vertexNormals.push(p.clone(),p.clone(),p.clone()),this.faces.push(A),this.faceVertexUvs[0].push([x.clone(),y,z.clone()])}this.computeCentroids()},e.PlaneGeometry.prototype=Object.create(e.Geometry.prototype),e.RingGeometry=function(a,b,c,d,f,g){e.Geometry.call(this),this.className="RingGeometry",a=a||0,b=b||50,f=void 0!==f?f:0,g=void 0!==g?g:2*Math.PI,c=void 0!==c?Math.max(3,c):8,d=void 0!==d?Math.max(3,d):8;var h,i,j=[],k=a,l=(b-a)/d;for(h=0;d>=h;h++){for(i=0;c>=i;i++){var m=new e.Vector3,n=f+i/c*g;m.x=k*Math.cos(n),m.y=k*Math.sin(n),this.vertices.push(m),j.push(new e.Vector2((m.x/b+1)/2,(m.y/b+1)/2))}k+=l}var o=new e.Vector3(0,0,1);for(h=0;d>h;h++){var p=h*c;for(i=0;c>=i;i++){var n=i+p,q=n+h,r=n+c+h,s=n+c+1+h;this.faces.push(new e.Face3(q,r,s,[o.clone(),o.clone(),o.clone()])),this.faceVertexUvs[0].push([j[q].clone(),j[r].clone(),j[s].clone()]),q=n+h,r=n+c+1+h,s=n+1+h,this.faces.push(new e.Face3(q,r,s,[o.clone(),o.clone(),o.clone()])),this.faceVertexUvs[0].push([j[q].clone(),j[r].clone(),j[s].clone()])}}this.computeCentroids(),this.computeFaceNormals(),this.boundingSphere=new e.Sphere(new e.Vector3,k)},e.RingGeometry.prototype=Object.create(e.Geometry.prototype),e.SphereGeometry=function(a,b,c,d,f,g,h){e.Geometry.call(this),this.className="SphereGeometry",this.radius=a=a||50,this.widthSegments=b=Math.max(3,Math.floor(b)||8),this.heightSegments=c=Math.max(2,Math.floor(c)||6),this.phiStart=d=void 0!==d?d:0,this.phiLength=f=void 0!==f?f:2*Math.PI,this.thetaStart=g=void 0!==g?g:0,this.thetaLength=h=void 0!==h?h:Math.PI;var i,j,k=[],l=[];for(j=0;c>=j;j++){var m=[],n=[];for(i=0;b>=i;i++){var o=i/b,p=j/c,q=new e.Vector3;q.x=-a*Math.cos(d+o*f)*Math.sin(g+p*h),q.y=a*Math.cos(g+p*h),q.z=a*Math.sin(d+o*f)*Math.sin(g+p*h),this.vertices.push(q),m.push(this.vertices.length-1),n.push(new e.Vector2(o,1-p))}k.push(m),l.push(n)}for(j=0;jp;p++)for(this.grid[p]=[],k=p/(C-1),o=a.getPointAt(k),h=F[p],i=G[p],j=H[p],q=0;q=h&&(g=h,m.set(1,0,0)),g>=i&&(g=i,m.set(0,1,0)),g>=j&&m.set(0,0,1),q.crossVectors(n[0],m).normalize(),o[0].crossVectors(n[0],q),p[0].crossVectors(n[0],o[0])}var f,g,h,i,j,k,l,m=(new e.Vector3,new e.Vector3),n=(new e.Vector3,[]),o=[],p=[],q=new e.Vector3,r=new e.Matrix4,s=b+1,t=1e-4;for(this.tangents=n,this.normals=o,this.binormals=p,k=0;s>k;k++)l=k/(s-1),n[k]=a.getTangentAt(l),n[k].normalize();for(d(),k=1;s>k;k++)o[k]=o[k-1].clone(),p[k]=p[k-1].clone(),q.crossVectors(n[k-1],n[k]),q.length()>t&&(q.normalize(),f=Math.acos(e.Math.clamp(n[k-1].dot(n[k]),-1,1)),o[k].applyMatrix4(r.makeRotationAxis(q,f))),p[k].crossVectors(n[k],o[k]);if(c)for(f=Math.acos(e.Math.clamp(o[0].dot(o[s-1]),-1,1)),f/=s-1,n[0].dot(q.crossVectors(o[0],o[s-1]))>0&&(f=-f),k=1;s>k;k++)o[k].applyMatrix4(r.makeRotationAxis(n[k],f*k)),p[k].crossVectors(n[k],o[k])},e.PolyhedronGeometry=function(a,b,c,d){function f(a){var b=a.normalize().clone();b.index=l.vertices.push(b)-1;var c=i(a)/2/Math.PI+.5,d=j(a)/Math.PI+.5;return b.uv=new e.Vector2(c,1-d),b}function g(a,b,c){var d=new e.Face3(a.index,b.index,c.index,[a.clone(),b.clone(),c.clone()]);d.centroid.add(a).add(b).add(c).divideScalar(3),l.faces.push(d);var f=i(d.centroid);l.faceVertexUvs[0].push([k(a.uv,a,f),k(b.uv,b,f),k(c.uv,c,f)])}function h(a,b){for(var c=Math.pow(2,b),d=(Math.pow(4,b),f(l.vertices[a.a])),e=f(l.vertices[a.b]),h=f(l.vertices[a.c]),i=[],j=0;c>=j;j++){i[j]=[];for(var k=f(d.clone().lerp(h,j/c)),m=f(e.clone().lerp(h,j/c)),n=c-j,o=0;n>=o;o++)0==o&&j==c?i[j][o]=k:i[j][o]=f(k.clone().lerp(m,o/n))}for(var j=0;c>j;j++)for(var o=0;2*(c-j)-1>o;o++){var p=Math.floor(o/2);o%2==0?g(i[j][p+1],i[j+1][p],i[j][p]):g(i[j][p+1],i[j+1][p+1],i[j+1][p])}}function i(a){return Math.atan2(a.z,-a.x)}function j(a){return Math.atan2(-a.y,Math.sqrt(a.x*a.x+a.z*a.z))}function k(a,b,c){return 0>c&&1===a.x&&(a=new e.Vector2(a.x-1,a.y)),0===b.x&&0===b.z&&(a=new e.Vector2(c/2/Math.PI+.5,a.y)),a.clone()}e.Geometry.call(this),this.className="PolyhedronGeometry",c=c||1,d=d||0;for(var l=this,m=0,n=a.length;n>m;m++)f(new e.Vector3(a[m][0],a[m][1],a[m][2]));for(var o=this.vertices,p=[],m=0,n=b.length;n>m;m++){var q=o[b[m][0]],r=o[b[m][1]],s=o[b[m][2]];p[m]=new e.Face3(q.index,r.index,s.index,[q.clone(),r.clone(),s.clone()])}for(var m=0,n=p.length;n>m;m++)h(p[m],d);for(var m=0,n=this.faceVertexUvs[0].length;n>m;m++){var t=this.faceVertexUvs[0][m],u=t[0].x,v=t[1].x,w=t[2].x,x=Math.max(u,Math.max(v,w)),y=Math.min(u,Math.min(v,w));x>.9&&.1>y&&(.2>u&&(t[0].x+=1),.2>v&&(t[1].x+=1),.2>w&&(t[2].x+=1))}for(var m=0,n=this.vertices.length;n>m;m++)this.vertices[m].multiplyScalar(c);this.mergeVertices(),this.computeCentroids(),this.computeFaceNormals(),this.boundingSphere=new e.Sphere(new e.Vector3,c)},e.PolyhedronGeometry.prototype=Object.create(e.Geometry.prototype),e.IcosahedronGeometry=function(a,b){this.radius=a,this.detail=b;var c=(1+Math.sqrt(5))/2,d=[[-1,c,0],[1,c,0],[-1,-c,0],[1,-c,0],[0,-1,c],[0,1,c],[0,-1,-c],[0,1,-c],[c,0,-1],[c,0,1],[-c,0,-1],[-c,0,1]],f=[[0,11,5],[0,5,1],[0,1,7],[0,7,10],[0,10,11],[1,5,9],[5,11,4],[11,10,2],[10,7,6],[7,1,8],[3,9,4],[3,4,2],[3,2,6],[3,6,8],[3,8,9],[4,9,5],[2,4,11],[6,2,10],[8,6,7],[9,8,1]];e.PolyhedronGeometry.call(this,d,f,a,b),this.className="IcosahedronGeometry"},e.IcosahedronGeometry.prototype=Object.create(e.Geometry.prototype),e.OctahedronGeometry=function(a,b){var c=[[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]],d=[[0,2,4],[0,4,3],[0,3,5],[0,5,2],[1,2,5],[1,5,3],[1,3,4],[1,4,2]];e.PolyhedronGeometry.call(this,c,d,a,b),this.className="OctahedronGeometry"},e.OctahedronGeometry.prototype=Object.create(e.Geometry.prototype),e.TetrahedronGeometry=function(a,b){this.className="TetrahedronGeometry";var c=[[1,1,1],[-1,-1,1],[-1,1,-1],[1,-1,-1]],d=[[2,1,0],[0,3,2],[1,3,0],[2,3,1]];e.PolyhedronGeometry.call(this,c,d,a,b)},e.TetrahedronGeometry.prototype=Object.create(e.Geometry.prototype),e.ParametricGeometry=function(a,b,c){e.Geometry.call(this),this.className="ParametricGeometry";var d,f,g,h,i,j=this.vertices,k=this.faces,l=this.faceVertexUvs[0],m=b+1;for(d=0;c>=d;d++)for(i=d/c,f=0;b>=f;f++)h=f/b,g=a(h,i),j.push(g);var n,o,p,q,r,s,t,u;for(d=0;c>d;d++)for(f=0;b>f;f++)n=d*m+f,o=d*m+f+1,p=(d+1)*m+f+1,q=(d+1)*m+f,r=new e.Vector2(f/b,d/c),s=new e.Vector2((f+1)/b,d/c),t=new e.Vector2((f+1)/b,(d+1)/c),u=new e.Vector2(f/b,(d+1)/c),k.push(new e.Face3(n,o,q)),l.push([r,s,u]),k.push(new e.Face3(o,p,q)),l.push([s.clone(),t,u.clone()]);this.computeCentroids(),this.computeFaceNormals(),this.computeVertexNormals()},e.ParametricGeometry.prototype=Object.create(e.Geometry.prototype),e.AxisHelper=function(a){a=a||1;var b=new e.Geometry;b.vertices.push(new e.Vector3,new e.Vector3(a,0,0),new e.Vector3,new e.Vector3(0,a,0),new e.Vector3,new e.Vector3(0,0,a)),b.colors.push(new e.Color(16711680),new e.Color(16755200),new e.Color(65280),new e.Color(11206400),new e.Color(255),new e.Color(43775));var c=new e.LineBasicMaterial({vertexColors:e.VertexColors});e.Line.call(this,b,c,e.LinePieces),this.className="AxisHelper"},e.AxisHelper.prototype=Object.create(e.Line.prototype),e.ArrowHelper=function(a,b,c,d,f,g){e.Object3D.call(this),this.className="ArrowHelper",void 0===d&&(d=16776960),void 0===c&&(c=1),void 0===f&&(f=.2*c),void 0===g&&(g=.2*f),this.position=b;var h=new e.Geometry;h.vertices.push(new e.Vector3(0,0,0)),h.vertices.push(new e.Vector3(0,1,0)),this.line=new e.Line(h,new e.LineBasicMaterial({color:d})),this.line.matrixAutoUpdate=!1,this.add(this.line);var i=new e.CylinderGeometry(0,.5,1,5,1);i.applyMatrix((new e.Matrix4).makeTranslation(0,-.5,0)),this.cone=new e.Mesh(i,new e.MeshBasicMaterial({color:d})),this.cone.matrixAutoUpdate=!1,this.add(this.cone),this.setDirection(a),this.setLength(c,f,g)},e.ArrowHelper.prototype=Object.create(e.Object3D.prototype),e.ArrowHelper.prototype.setDirection=function(){var a,b=new e.Vector3;return function(c){c.y>.99999?this.quaternion.set(0,0,0,1):c.y<-.99999?this.quaternion.set(1,0,0,0):(b.set(c.z,0,-c.x).normalize(),a=Math.acos(c.y),this.quaternion.setFromAxisAngle(b,a))}}(),e.ArrowHelper.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a),void 0===c&&(c=.2*b),this.line.scale.set(1,a,1),this.line.updateMatrix(),this.cone.scale.set(c,b,c),this.cone.position.y=a,this.cone.updateMatrix()},e.ArrowHelper.prototype.setColor=function(a){this.line.material.color.setHex(a),this.cone.material.color.setHex(a)},e.BoxHelper=function(a){var b=[new e.Vector3(1,1,1),new e.Vector3(-1,1,1),new e.Vector3(-1,-1,1),new e.Vector3(1,-1,1),new e.Vector3(1,1,-1),new e.Vector3(-1,1,-1),new e.Vector3(-1,-1,-1),new e.Vector3(1,-1,-1)];this.vertices=b;var c=new e.Geometry;c.vertices.push(b[0],b[1],b[1],b[2],b[2],b[3],b[3],b[0],b[4],b[5],b[5],b[6],b[6],b[7],b[7],b[4],b[0],b[4],b[1],b[5],b[2],b[6],b[3],b[7]),e.Line.call(this,c,new e.LineBasicMaterial({color:16776960}),e.LinePieces),void 0!==a&&this.update(a)},e.BoxHelper.prototype=Object.create(e.Line.prototype),e.BoxHelper.prototype.update=function(a){var b=a.geometry;null===b.boundingBox&&b.computeBoundingBox();var c=b.boundingBox.min,d=b.boundingBox.max,e=this.vertices;e[0].set(d.x,d.y,d.z),e[1].set(c.x,d.y,d.z),e[2].set(c.x,c.y,d.z),e[3].set(d.x,c.y,d.z),e[4].set(d.x,d.y,c.z),e[5].set(c.x,d.y,c.z),e[6].set(c.x,c.y,c.z),e[7].set(d.x,c.y,c.z),this.geometry.computeBoundingSphere(),this.geometry.verticesNeedUpdate=!0,this.matrixAutoUpdate=!1,this.matrixWorld=a.matrixWorld},e.BoundingBoxHelper=function(a,b){var c=void 0!==b?b:8947848;this.object=a,this.box=new e.Box3,e.Mesh.call(this,new e.BoxGeometry(1,1,1),new e.MeshBasicMaterial({color:c,wireframe:!0}))},e.BoundingBoxHelper.prototype=Object.create(e.Mesh.prototype),e.BoundingBoxHelper.prototype.update=function(){this.box.setFromObject(this.object),this.box.size(this.scale),this.box.center(this.position)},e.CameraHelper=function(a){function b(a,b,d){c(a,d),c(b,d)}function c(a,b){d.vertices.push(new e.Vector3),d.colors.push(new e.Color(b)),void 0===g[a]&&(g[a]=[]),g[a].push(d.vertices.length-1)}var d=new e.Geometry,f=new e.LineBasicMaterial({color:16777215,vertexColors:e.FaceColors}),g={},h=16755200,i=16711680,j=43775,k=16777215,l=3355443;b("n1","n2",h),b("n2","n4",h),b("n4","n3",h),b("n3","n1",h),b("f1","f2",h),b("f2","f4",h),b("f4","f3",h),b("f3","f1",h),b("n1","f1",h),b("n2","f2",h),b("n3","f3",h),b("n4","f4",h),b("p","n1",i),b("p","n2",i),b("p","n3",i),b("p","n4",i),b("u1","u2",j),b("u2","u3",j),b("u3","u1",j),b("c","t",k),b("p","c",l),b("cn1","cn2",l),b("cn3","cn4",l),b("cf1","cf2",l),b("cf3","cf4",l),e.Line.call(this,d,f,e.LinePieces),this.camera=a,this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1,this.pointMap=g,this.update()},e.CameraHelper.prototype=Object.create(e.Line.prototype),e.CameraHelper.prototype.update=function(){var a=new e.Vector3,b=new e.Camera,c=new e.Projector;return function(){function d(d,f,g,h){a.set(f,g,h),c.unprojectVector(a,b);var i=e.pointMap[d];if(void 0!==i)for(var j=0,k=i.length;k>j;j++)e.geometry.vertices[i[j]].copy(a)}var e=this,f=1,g=1;b.projectionMatrix.copy(this.camera.projectionMatrix),d("c",0,0,-1),d("t",0,0,1),d("n1",-f,-g,-1),d("n2",f,-g,-1),d("n3",-f,g,-1),d("n4",f,g,-1),d("f1",-f,-g,1),d("f2",f,-g,1),d("f3",-f,g,1),d("f4",f,g,1),d("u1",.7*f,1.1*g,-1),d("u2",.7*-f,1.1*g,-1),d("u3",0,2*g,-1),d("cf1",-f,0,1),d("cf2",f,0,1),d("cf3",0,-g,1),d("cf4",0,g,1),d("cn1",-f,0,-1),d("cn2",f,0,-1),d("cn3",0,-g,-1),d("cn4",0,g,-1),this.geometry.verticesNeedUpdate=!0}}(),e.DirectionalLightHelper=function(a,b){e.Object3D.call(this),this.light=a,this.light.updateMatrixWorld(),this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1,b=b||1;var c=new e.PlaneGeometry(b,b),d=new e.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity),this.lightPlane=new e.Mesh(c,d),this.add(this.lightPlane),c=new e.Geometry,c.vertices.push(new e.Vector3),c.vertices.push(new e.Vector3),d=new e.LineBasicMaterial({fog:!1}),d.color.copy(this.light.color).multiplyScalar(this.light.intensity),this.targetLine=new e.Line(c,d),this.add(this.targetLine),this.update()},e.DirectionalLightHelper.prototype=Object.create(e.Object3D.prototype),e.DirectionalLightHelper.prototype.dispose=function(){this.lightPlane.geometry.dispose(),this.lightPlane.material.dispose(),this.targetLine.geometry.dispose(),this.targetLine.material.dispose()},e.DirectionalLightHelper.prototype.update=function(){var a=new e.Vector3,b=new e.Vector3,c=new e.Vector3;return function(){a.setFromMatrixPosition(this.light.matrixWorld),b.setFromMatrixPosition(this.light.target.matrixWorld),c.subVectors(b,a),this.lightPlane.lookAt(c),this.lightPlane.material.color.copy(this.light.color).multiplyScalar(this.light.intensity),this.targetLine.geometry.vertices[1].copy(c),this.targetLine.geometry.verticesNeedUpdate=!0,this.targetLine.material.color.copy(this.lightPlane.material.color)}}(),e.EdgesHelper=function(a,b){var c=void 0!==b?b:16777215,d=[0,0],f={},g=function(a,b){return a-b},h=["a","b","c"],i=new e.BufferGeometry,j=a.geometry.clone();j.mergeVertices(),j.computeFaceNormals();for(var k=j.vertices,l=j.faces,m=0,n=0,o=l.length;o>n;n++)for(var p=l[n],q=0;3>q;q++){d[0]=p[h[q]],d[1]=p[h[(q+1)%3]],d.sort(g);var r=d.toString();void 0===f[r]?(f[r]={vert1:d[0],vert2:d[1],face1:n,face2:void 0},m++):f[r].face2=n}i.addAttribute("position",Float32Array,2*m,3);var s=i.attributes.position.array,t=0;for(var r in f){var u=f[r];if(void 0===u.face2||l[u.face1].normal.dot(l[u.face2].normal)<.9999){var v=k[u.vert1];s[t++]=v.x,s[t++]=v.y,s[t++]=v.z,v=k[u.vert2],s[t++]=v.x,s[t++]=v.y,s[t++]=v.z}}e.Line.call(this,i,new e.LineBasicMaterial({color:c}),e.LinePieces),this.matrixAutoUpdate=!1,this.matrixWorld=a.matrixWorld},e.EdgesHelper.prototype=Object.create(e.Line.prototype),e.FaceNormalsHelper=function(a,b,c,d){this.object=a,this.size=void 0!==b?b:1;for(var f=void 0!==c?c:16776960,g=void 0!==d?d:1,h=new e.Geometry,i=this.object.geometry.faces,j=0,k=i.length;k>j;j++)h.vertices.push(new e.Vector3),h.vertices.push(new e.Vector3);e.Line.call(this,h,new e.LineBasicMaterial({color:f,linewidth:g}),e.LinePieces),this.matrixAutoUpdate=!1,this.normalMatrix=new e.Matrix3,this.update()},e.FaceNormalsHelper.prototype=Object.create(e.Line.prototype),e.FaceNormalsHelper.prototype.update=function(a){var b=new e.Vector3;return function(a){this.object.updateMatrixWorld(!0),this.normalMatrix.getNormalMatrix(this.object.matrixWorld);for(var c=this.geometry.vertices,d=this.object.geometry.faces,e=this.object.matrixWorld,f=0,g=d.length;g>f;f++){var h=d[f];b.copy(h.normal).applyMatrix3(this.normalMatrix).normalize().multiplyScalar(this.size);var i=2*f;c[i].copy(h.centroid).applyMatrix4(e),c[i+1].addVectors(c[i],b)}return this.geometry.verticesNeedUpdate=!0,this}}(),e.GridHelper=function(a,b){var c=new e.Geometry,d=new e.LineBasicMaterial({vertexColors:e.VertexColors});this.color1=new e.Color(4473924),this.color2=new e.Color(8947848);for(var f=-a;a>=f;f+=b){c.vertices.push(new e.Vector3(-a,0,f),new e.Vector3(a,0,f),new e.Vector3(f,0,-a),new e.Vector3(f,0,a));var g=0===f?this.color1:this.color2;c.colors.push(g,g,g,g)}e.Line.call(this,c,d,e.LinePieces)},e.GridHelper.prototype=Object.create(e.Line.prototype),e.GridHelper.prototype.setColors=function(a,b){this.color1.set(a),this.color2.set(b),this.geometry.colorsNeedUpdate=!0},e.HemisphereLightHelper=function(a,b,c,d){e.Object3D.call(this),this.light=a,this.light.updateMatrixWorld(),this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1,this.colors=[new e.Color,new e.Color];var f=new e.SphereGeometry(b,4,2);f.applyMatrix((new e.Matrix4).makeRotationX(-Math.PI/2));for(var g=0,h=8;h>g;g++)f.faces[g].color=this.colors[4>g?0:1];var i=new e.MeshBasicMaterial({vertexColors:e.FaceColors,wireframe:!0});this.lightSphere=new e.Mesh(f,i),this.add(this.lightSphere),this.update()},e.HemisphereLightHelper.prototype=Object.create(e.Object3D.prototype),e.HemisphereLightHelper.prototype.dispose=function(){this.lightSphere.geometry.dispose(),this.lightSphere.material.dispose()},e.HemisphereLightHelper.prototype.update=function(){var a=new e.Vector3;return function(){this.colors[0].copy(this.light.color).multiplyScalar(this.light.intensity),this.colors[1].copy(this.light.groundColor).multiplyScalar(this.light.intensity),this.lightSphere.lookAt(a.setFromMatrixPosition(this.light.matrixWorld).negate()),this.lightSphere.geometry.colorsNeedUpdate=!0}}(),e.PointLightHelper=function(a,b){this.light=a,this.light.updateMatrixWorld();var c=new e.SphereGeometry(b,4,2),d=new e.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity),e.Mesh.call(this,c,d),this.matrixWorld=this.light.matrixWorld,this.matrixAutoUpdate=!1},e.PointLightHelper.prototype=Object.create(e.Mesh.prototype),e.PointLightHelper.prototype.dispose=function(){this.geometry.dispose(),this.material.dispose()},e.PointLightHelper.prototype.update=function(){this.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)},e.SpotLightHelper=function(a){e.Object3D.call(this),this.light=a,this.light.updateMatrixWorld(),this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1;var b=new e.CylinderGeometry(0,1,1,8,1,!0);b.applyMatrix((new e.Matrix4).makeTranslation(0,-.5,0)),b.applyMatrix((new e.Matrix4).makeRotationX(-Math.PI/2));var c=new e.MeshBasicMaterial({wireframe:!0,fog:!1});this.cone=new e.Mesh(b,c),this.add(this.cone),this.update()},e.SpotLightHelper.prototype=Object.create(e.Object3D.prototype),e.SpotLightHelper.prototype.dispose=function(){this.cone.geometry.dispose(),this.cone.material.dispose()},e.SpotLightHelper.prototype.update=function(){var a=new e.Vector3,b=new e.Vector3;return function(){var c=this.light.distance?this.light.distance:1e4,d=c*Math.tan(this.light.angle);this.cone.scale.set(d,d,c),a.setFromMatrixPosition(this.light.matrixWorld),b.setFromMatrixPosition(this.light.target.matrixWorld),this.cone.lookAt(b.sub(a)),this.cone.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)}}(),e.VertexNormalsHelper=function(a,b,c,d){this.object=a,this.size=void 0!==b?b:1;for(var f=void 0!==c?c:16711680,g=void 0!==d?d:1,h=new e.Geometry,i=(a.geometry.vertices,a.geometry.faces),j=0,k=i.length;k>j;j++)for(var l=i[j],m=0,n=l.vertexNormals.length;n>m;m++)h.vertices.push(new e.Vector3),h.vertices.push(new e.Vector3);e.Line.call(this,h,new e.LineBasicMaterial({color:f,linewidth:g}),e.LinePieces),this.matrixAutoUpdate=!1,this.normalMatrix=new e.Matrix3,this.update()},e.VertexNormalsHelper.prototype=Object.create(e.Line.prototype),e.VertexNormalsHelper.prototype.update=function(a){var b=new e.Vector3;return function(a){var c=["a","b","c","d"];this.object.updateMatrixWorld(!0),this.normalMatrix.getNormalMatrix(this.object.matrixWorld);for(var d=this.geometry.vertices,e=this.object.geometry.vertices,f=this.object.geometry.faces,g=this.object.matrixWorld,h=0,i=0,j=f.length;j>i;i++)for(var k=f[i],l=0,m=k.vertexNormals.length;m>l;l++){var n=k[c[l]],o=e[n],p=k.vertexNormals[l];d[h].copy(o).applyMatrix4(g),b.copy(p).applyMatrix3(this.normalMatrix).normalize().multiplyScalar(this.size),b.add(d[h]),h+=1,d[h].copy(b),h+=1}return this.geometry.verticesNeedUpdate=!0,this}}(),e.VertexTangentsHelper=function(a,b,c,d){this.object=a,this.size=void 0!==b?b:1;for(var f=void 0!==c?c:255,g=void 0!==d?d:1,h=new e.Geometry,i=(a.geometry.vertices,a.geometry.faces),j=0,k=i.length;k>j;j++)for(var l=i[j],m=0,n=l.vertexTangents.length;n>m;m++)h.vertices.push(new e.Vector3),h.vertices.push(new e.Vector3);e.Line.call(this,h,new e.LineBasicMaterial({color:f,linewidth:g}),e.LinePieces),this.matrixAutoUpdate=!1,this.update()},e.VertexTangentsHelper.prototype=Object.create(e.Line.prototype),e.VertexTangentsHelper.prototype.update=function(a){var b=new e.Vector3;return function(a){var c=["a","b","c","d"];this.object.updateMatrixWorld(!0);for(var d=this.geometry.vertices,e=this.object.geometry.vertices,f=this.object.geometry.faces,g=this.object.matrixWorld,h=0,i=0,j=f.length;j>i;i++)for(var k=f[i],l=0,m=k.vertexTangents.length;m>l;l++){var n=k[c[l]],o=e[n],p=k.vertexTangents[l];d[h].copy(o).applyMatrix4(g),b.copy(p).transformDirection(g).multiplyScalar(this.size),b.add(d[h]),h+=1,d[h].copy(b),h+=1}return this.geometry.verticesNeedUpdate=!0,this}}(),e.WireframeHelper=function(a,b){var c=void 0!==b?b:16777215,d=[0,0],f={},g=function(a,b){return a-b},h=["a","b","c"],i=new e.BufferGeometry;if(a.geometry instanceof e.Geometry){for(var j=a.geometry.vertices,k=a.geometry.faces,l=0,m=new Uint32Array(6*k.length),n=0,o=k.length;o>n;n++)for(var p=k[n],q=0;3>q;q++){d[0]=p[h[q]],d[1]=p[h[(q+1)%3]],d.sort(g);var r=d.toString();void 0===f[r]&&(m[2*l]=d[0],m[2*l+1]=d[1],f[r]=!0,l++)}i.addAttribute("position",Float32Array,2*l,3);for(var s=i.attributes.position.array,n=0,o=l;o>n;n++)for(var q=0;2>q;q++){var t=j[m[2*n+q]],u=6*n+3*q;s[u+0]=t.x,s[u+1]=t.y,s[u+2]=t.z}}else if(a.geometry instanceof e.BufferGeometry&&void 0!==a.geometry.attributes.index){for(var j=a.geometry.attributes.position.array,v=a.geometry.attributes.index.array,w=a.geometry.offsets,l=0,m=new Uint32Array(2*v.length),x=0,y=w.length;y>x;++x)for(var z=w[x].start,A=w[x].count,u=w[x].index,n=z,B=z+A;B>n;n+=3)for(var q=0;3>q;q++){d[0]=u+v[n+q],d[1]=u+v[n+(q+1)%3],d.sort(g);var r=d.toString();void 0===f[r]&&(m[2*l]=d[0],m[2*l+1]=d[1],f[r]=!0,l++)}i.addAttribute("position",Float32Array,2*l,3);for(var s=i.attributes.position.array,n=0,o=l;o>n;n++)for(var q=0;2>q;q++){var u=6*n+3*q,C=3*m[2*n+q];s[u+0]=j[C],s[u+1]=j[C+1],s[u+2]=j[C+2]}}else if(a.geometry instanceof e.BufferGeometry){var j=a.geometry.attributes.position.array,l=j.length/3,D=l/3;i.addAttribute("position",Float32Array,2*l,3);for(var s=i.attributes.position.array,n=0,o=D;o>n;n++)for(var q=0;3>q;q++){var u=18*n+6*q,E=9*n+3*q;s[u+0]=j[E],s[u+1]=j[E+1],s[u+2]=j[E+2];var C=9*n+3*((q+1)%3);s[u+3]=j[C],s[u+4]=j[C+1],s[u+5]=j[C+2]}}e.Line.call(this,i,new e.LineBasicMaterial({color:c}),e.LinePieces),this.matrixAutoUpdate=!1,this.matrixWorld=a.matrixWorld},e.WireframeHelper.prototype=Object.create(e.Line.prototype),e.ImmediateRenderObject=function(){e.Object3D.call(this),this.render=function(a){}},e.ImmediateRenderObject.prototype=Object.create(e.Object3D.prototype),e.LensFlare=function(a,b,c,d,f){ +e.Object3D.call(this),this.lensFlares=[],this.positionScreen=new e.Vector3,this.customUpdateCallback=void 0,void 0!==a&&this.add(a,b,c,d,f)},e.LensFlare.prototype=Object.create(e.Object3D.prototype),e.LensFlare.prototype.add=function(a,b,c,d,f,g){void 0===b&&(b=-1),void 0===c&&(c=0),void 0===g&&(g=1),void 0===f&&(f=new e.Color(16777215)),void 0===d&&(d=e.NormalBlending),c=Math.min(c,Math.max(0,c)),this.lensFlares.push({texture:a,size:b,distance:c,x:0,y:0,z:0,scale:1,rotation:1,opacity:g,color:f,blending:d})},e.LensFlare.prototype.updateLensFlares=function(){var a,b,c=this.lensFlares.length,d=2*-this.positionScreen.x,e=2*-this.positionScreen.y;for(a=0;c>a;a++)b=this.lensFlares[a],b.x=this.positionScreen.x+d*b.distance,b.y=this.positionScreen.y+e*b.distance,b.wantedRotation=b.x*Math.PI*.25,b.rotation+=.25*(b.wantedRotation-b.rotation)},e.MorphBlendMesh=function(a,b){e.Mesh.call(this,a,b),this.animationsMap={},this.animationsList=[];var c=this.geometry.morphTargets.length,d="__default",f=0,g=c-1,h=c/1;this.createAnimation(d,f,g,h),this.setAnimationWeight(d,1)},e.MorphBlendMesh.prototype=Object.create(e.Mesh.prototype),e.MorphBlendMesh.prototype.createAnimation=function(a,b,c,d){var e={startFrame:b,endFrame:c,length:c-b+1,fps:d,duration:(c-b)/d,lastFrame:0,currentFrame:0,active:!1,time:0,direction:1,weight:1,directionBackwards:!1,mirroredLoop:!1};this.animationsMap[a]=e,this.animationsList.push(e)},e.MorphBlendMesh.prototype.autoCreateAnimations=function(a){for(var b,c=/([a-z]+)(\d+)/,d={},e=this.geometry,f=0,g=e.morphTargets.length;g>f;f++){var h=e.morphTargets[f],i=h.name.match(c);if(i&&i.length>1){var j=i[1];i[2];d[j]||(d[j]={start:1/0,end:-(1/0)});var k=d[j];fk.end&&(k.end=f),b||(b=j)}}for(var j in d){var k=d[j];this.createAnimation(j,k.start,k.end,a)}this.firstAnimation=b},e.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){var b=this.animationsMap[a];b&&(b.direction=1,b.directionBackwards=!1)},e.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){var b=this.animationsMap[a];b&&(b.direction=-1,b.directionBackwards=!0)},e.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)},e.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)},e.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)},e.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)},e.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0,c=this.animationsMap[a];return c&&(b=c.time),b},e.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1,c=this.animationsMap[a];return c&&(b=c.duration),b},e.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):e.onwarning("animation["+a+"] undefined")},e.MorphBlendMesh.prototype.stopAnimation=function(a){var b=this.animationsMap[a];b&&(b.active=!1)},e.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;c>b;b++){var d=this.animationsList[b];if(d.active){var f=d.duration/d.length;d.time+=d.direction*a,d.mirroredLoop?(d.time>d.duration||d.time<0)&&(d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),d.time<0&&(d.time=0,d.directionBackwards=!1)):(d.time=d.time%d.duration,d.time<0&&(d.time+=d.duration));var g=d.startFrame+e.Math.clamp(Math.floor(d.time/f),0,d.length-1),h=d.weight;g!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*h,this.morphTargetInfluences[g]=0,d.lastFrame=d.currentFrame,d.currentFrame=g);var i=d.time%f/f;d.directionBackwards&&(i=1-i),this.morphTargetInfluences[d.currentFrame]=i*h,this.morphTargetInfluences[d.lastFrame]=(1-i)*h}}},e.LensFlarePlugin=function(){function a(a,c){var d=b.createProgram(),e=b.createShader(b.FRAGMENT_SHADER),f=b.createShader(b.VERTEX_SHADER),g="precision "+c+" float;\n";return b.shaderSource(e,g+a.fragmentShader),b.shaderSource(f,g+a.vertexShader),b.compileShader(e),b.compileShader(f),b.attachShader(d,e),b.attachShader(d,f),b.linkProgram(d),d}var b,c,d,f={};this.init=function(g){b=g.context,c=g,d=g.getPrecision(),f.vertices=new Float32Array(16),f.faces=new Uint16Array(6);var h=0;f.vertices[h++]=-1,f.vertices[h++]=-1,f.vertices[h++]=0,f.vertices[h++]=0,f.vertices[h++]=1,f.vertices[h++]=-1,f.vertices[h++]=1,f.vertices[h++]=0,f.vertices[h++]=1,f.vertices[h++]=1,f.vertices[h++]=1,f.vertices[h++]=1,f.vertices[h++]=-1,f.vertices[h++]=1,f.vertices[h++]=0,f.vertices[h++]=1,h=0,f.faces[h++]=0,f.faces[h++]=1,f.faces[h++]=2,f.faces[h++]=0,f.faces[h++]=2,f.faces[h++]=3,f.vertexBuffer=b.createBuffer(),f.elementBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,f.vertexBuffer),b.bufferData(b.ARRAY_BUFFER,f.vertices,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,f.elementBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,f.faces,b.STATIC_DRAW),f.tempTexture=b.createTexture(),f.occlusionTexture=b.createTexture(),b.bindTexture(b.TEXTURE_2D,f.tempTexture),b.texImage2D(b.TEXTURE_2D,0,b.RGB,16,16,0,b.RGB,b.UNSIGNED_BYTE,null),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST),b.bindTexture(b.TEXTURE_2D,f.occlusionTexture),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,16,16,0,b.RGBA,b.UNSIGNED_BYTE,null),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST),b.getParameter(b.MAX_VERTEX_TEXTURE_IMAGE_UNITS)<=0?(f.hasVertexTexture=!1,f.program=a(e.ShaderFlares.lensFlare,d)):(f.hasVertexTexture=!0,f.program=a(e.ShaderFlares.lensFlareVertexTexture,d)),f.attributes={},f.uniforms={},f.attributes.vertex=b.getAttribLocation(f.program,"position"),f.attributes.uv=b.getAttribLocation(f.program,"uv"),f.uniforms.renderType=b.getUniformLocation(f.program,"renderType"),f.uniforms.map=b.getUniformLocation(f.program,"map"),f.uniforms.occlusionMap=b.getUniformLocation(f.program,"occlusionMap"),f.uniforms.opacity=b.getUniformLocation(f.program,"opacity"),f.uniforms.color=b.getUniformLocation(f.program,"color"),f.uniforms.scale=b.getUniformLocation(f.program,"scale"),f.uniforms.rotation=b.getUniformLocation(f.program,"rotation"),f.uniforms.screenPosition=b.getUniformLocation(f.program,"screenPosition")},this.render=function(a,d,g,h){var i=a.__webglFlares,j=i.length;if(j){var k=new e.Vector3,l=h/g,m=.5*g,n=.5*h,o=16/h,p=new e.Vector2(o*l,o),q=new e.Vector3(1,1,0),r=new e.Vector2(1,1),s=f.uniforms,t=f.attributes;b.useProgram(f.program),b.enableVertexAttribArray(f.attributes.vertex),b.enableVertexAttribArray(f.attributes.uv),b.uniform1i(s.occlusionMap,0),b.uniform1i(s.map,1),b.bindBuffer(b.ARRAY_BUFFER,f.vertexBuffer),b.vertexAttribPointer(t.vertex,2,b.FLOAT,!1,16,0),b.vertexAttribPointer(t.uv,2,b.FLOAT,!1,16,8),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,f.elementBuffer),b.disable(b.CULL_FACE),b.depthMask(!1);var u,v,w,x,y;for(u=0;j>u;u++)if(o=16/h,p.set(o*l,o),x=i[u],k.set(x.matrixWorld.elements[12],x.matrixWorld.elements[13],x.matrixWorld.elements[14]),k.applyMatrix4(d.matrixWorldInverse),k.applyProjection(d.projectionMatrix),q.copy(k),r.x=q.x*m+m,r.y=q.y*n+n,f.hasVertexTexture||r.x>0&&r.x0&&r.yv;v++)y=x.lensFlares[v],y.opacity>.001&&y.scale>.001&&(q.x=y.x,q.y=y.y,q.z=y.z,o=y.size*y.scale/h,p.x=o*l,p.y=o,b.uniform3f(s.screenPosition,q.x,q.y,q.z),b.uniform2f(s.scale,p.x,p.y),b.uniform1f(s.rotation,y.rotation),b.uniform1f(s.opacity,y.opacity),b.uniform3f(s.color,y.color.r,y.color.g,y.color.b),c.setBlending(y.blending,y.blendEquation,y.blendSrc,y.blendDst),c.setTexture(y.texture,1),b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0));b.enable(b.CULL_FACE),b.enable(b.DEPTH_TEST),b.depthMask(!0)}}},e.ShadowMapPlugin=function(){function a(a,b){var c=new e.DirectionalLight;c.isVirtual=!0,c.onlyShadow=!0,c.castShadow=!0,c.shadowCameraNear=a.shadowCameraNear,c.shadowCameraFar=a.shadowCameraFar,c.shadowCameraLeft=a.shadowCameraLeft,c.shadowCameraRight=a.shadowCameraRight,c.shadowCameraBottom=a.shadowCameraBottom,c.shadowCameraTop=a.shadowCameraTop,c.shadowCameraVisible=a.shadowCameraVisible,c.shadowDarkness=a.shadowDarkness,c.shadowBias=a.shadowCascadeBias[b],c.shadowMapWidth=a.shadowCascadeWidth[b],c.shadowMapHeight=a.shadowCascadeHeight[b],c.pointsWorld=[],c.pointsFrustum=[];for(var d=c.pointsWorld,f=c.pointsFrustum,g=0;8>g;g++)d[g]=new e.Vector3,f[g]=new e.Vector3;var h=a.shadowCascadeNearZ[b],i=a.shadowCascadeFarZ[b];return f[0].set(-1,-1,h),f[1].set(1,-1,h),f[2].set(-1,1,h),f[3].set(1,1,h),f[4].set(-1,-1,i),f[5].set(1,-1,i),f[6].set(-1,1,i),f[7].set(1,1,i),c}function b(a,b){var c=a.shadowCascadeArray[b];c.position.copy(a.position),c.target.position.copy(a.target.position),c.lookAt(c.target),c.shadowCameraVisible=a.shadowCameraVisible,c.shadowDarkness=a.shadowDarkness,c.shadowBias=a.shadowCascadeBias[b];var d=a.shadowCascadeNearZ[b],e=a.shadowCascadeFarZ[b],f=c.pointsFrustum;f[0].z=d,f[1].z=d,f[2].z=d,f[3].z=d,f[4].z=e,f[5].z=e,f[6].z=e,f[7].z=e}function c(a,b){var c=b.shadowCamera,d=b.pointsFrustum,f=b.pointsWorld;n.set(1/0,1/0,1/0),o.set(-(1/0),-(1/0),-(1/0));for(var g=0;8>g;g++){var h=f[g];h.copy(d[g]),e.ShadowMapPlugin.__projector.unprojectVector(h,a),h.applyMatrix4(c.matrixWorldInverse),h.xo.x&&(o.x=h.x),h.yo.y&&(o.y=h.y),h.zo.z&&(o.z=h.z)}c.left=n.x,c.right=o.x,c.top=o.y,c.bottom=n.y,c.updateProjectionMatrix()}function d(a){return a.material instanceof e.MeshFaceMaterial?a.material.materials[0]:a.material}var f,g,h,i,j,k,l=new e.Frustum,m=new e.Matrix4,n=new e.Vector3,o=new e.Vector3,p=new e.Vector3;this.init=function(a){f=a.context,g=a;var b=e.ShaderLib.depthRGBA,c=e.UniformsUtils.clone(b.uniforms);h=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c}),i=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c,morphTargets:!0}),j=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c,skinning:!0}),k=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c,morphTargets:!0,skinning:!0}),h._shadowPass=!0,i._shadowPass=!0,j._shadowPass=!0,k._shadowPass=!0},this.render=function(a,b){g.shadowMapEnabled&&g.shadowMapAutoUpdate&&this.update(a,b)},this.update=function(n,o){var q,r,s,t,u,v,w,x,y,z,A,B,C,D,E=[],F=0,G=null;for(f.clearColor(1,1,1,1),f.disable(f.BLEND),f.enable(f.CULL_FACE),f.frontFace(f.CCW),g.shadowMapCullFace===e.CullFaceFront?f.cullFace(f.FRONT):f.cullFace(f.BACK),g.setDepthTest(!0),q=0,r=n.__lights.length;r>q;q++)if(C=n.__lights[q],C.castShadow)if(C instanceof e.DirectionalLight&&C.shadowCascade)for(u=0;uq;q++){if(C=E[q],!C.shadowMap){var J=e.NearestFilter;g.shadowMapType===e.PCFSoftShadowMap&&(J=e.NearestFilter);var K={minFilter:J,magFilter:J,format:e.RGBAFormat};C.shadowMap=new e.WebGLRenderTarget(C.shadowMapWidth,C.shadowMapHeight,K),C.shadowMapSize=new e.Vector2(C.shadowMapWidth,C.shadowMapHeight),C.shadowMatrix=new e.Matrix4}if(!C.shadowCamera){if(C instanceof e.SpotLight)C.shadowCamera=new e.PerspectiveCamera(C.shadowCameraFov,C.shadowMapWidth/C.shadowMapHeight,C.shadowCameraNear,C.shadowCameraFar);else{if(!(C instanceof e.DirectionalLight)){e.onerror("Unsupported light type for shadow");continue}C.shadowCamera=new e.OrthographicCamera(C.shadowCameraLeft,C.shadowCameraRight,C.shadowCameraTop,C.shadowCameraBottom,C.shadowCameraNear,C.shadowCameraFar)}n.add(C.shadowCamera),n.autoUpdate===!0&&n.updateMatrixWorld()}for(C.shadowCameraVisible&&!C.cameraHelper&&(C.cameraHelper=new e.CameraHelper(C.shadowCamera),C.shadowCamera.add(C.cameraHelper)),C.isVirtual&&H.originalCamera==o&&c(o,C),v=C.shadowMap,w=C.shadowMatrix,x=C.shadowCamera,x.position.setFromMatrixPosition(C.matrixWorld),p.setFromMatrixPosition(C.target.matrixWorld),x.lookAt(p),x.updateMatrixWorld(),x.matrixWorldInverse.getInverse(x.matrixWorld),C.cameraHelper&&(C.cameraHelper.visible=C.shadowCameraVisible),C.shadowCameraVisible&&C.cameraHelper.update(),w.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1),w.multiply(x.projectionMatrix),w.multiply(x.matrixWorldInverse),m.multiplyMatrices(x.projectionMatrix,x.matrixWorldInverse),l.setFromMatrix(m),g.setRenderTarget(v),g.clear(),D=n.__webglObjects,s=0,t=D.length;t>s;s++)A=D[s],B=A.object,A.render=!1,B.visible&&B.castShadow&&((B instanceof e.Mesh||B instanceof e.ParticleSystem)&&B.frustumCulled&&!l.intersectsObject(B)||(B._modelViewMatrix.multiplyMatrices(x.matrixWorldInverse,B.matrixWorld),A.render=!0));var L,M,N;for(s=0,t=D.length;t>s;s++)A=D[s],A.render&&(B=A.object,y=A.buffer,L=d(B),M=void 0!==B.geometry.morphTargets&&B.geometry.morphTargets.length>0&&L.morphTargets,N=B instanceof e.SkinnedMesh&&L.skinning,z=B.customDepthMaterial?B.customDepthMaterial:N?M?k:j:M?i:h,y instanceof e.BufferGeometry?g.renderBufferDirect(x,n.__lights,G,z,y,B):g.renderBuffer(x,n.__lights,G,z,y,B));for(D=n.__webglObjectsImmediate,s=0,t=D.length;t>s;s++)A=D[s],B=A.object,B.visible&&B.castShadow&&(B._modelViewMatrix.multiplyMatrices(x.matrixWorldInverse,B.matrixWorld),g.renderImmediateObject(x,n.__lights,G,h,B))}var O=g.getClearColor(),P=g.getClearAlpha();f.clearColor(O.r,O.g,O.b,P),f.enable(f.BLEND),g.shadowMapCullFace===e.CullFaceFront&&f.cullFace(f.BACK)}},e.ShadowMapPlugin.__projector=new e.Projector,e.SpritePlugin=function(){function a(){var a=c.createProgram(),b=c.createShader(c.VERTEX_SHADER),e=c.createShader(c.FRAGMENT_SHADER);return c.shaderSource(b,["precision "+d.getPrecision()+" float;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform float rotation;","uniform vec2 scale;","uniform vec2 uvOffset;","uniform vec2 uvScale;","attribute vec2 position;","attribute vec2 uv;","varying vec2 vUV;","void main() {","vUV = uvOffset + uv * uvScale;","vec2 alignedPosition = position * scale;","vec2 rotatedPosition;","rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;","rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;","vec4 finalPosition;","finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );","finalPosition.xy += rotatedPosition;","finalPosition = projectionMatrix * finalPosition;","gl_Position = finalPosition;","}"].join("\n")),c.shaderSource(e,["precision "+d.getPrecision()+" float;","uniform vec3 color;","uniform sampler2D map;","uniform float opacity;","uniform int fogType;","uniform vec3 fogColor;","uniform float fogDensity;","uniform float fogNear;","uniform float fogFar;","uniform float alphaTest;","varying vec2 vUV;","void main() {","vec4 texture = texture2D( map, vUV );","if ( texture.a < alphaTest ) discard;","gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );","if ( fogType > 0 ) {","float depth = gl_FragCoord.z / gl_FragCoord.w;","float fogFactor = 0.0;","if ( fogType == 1 ) {","fogFactor = smoothstep( fogNear, fogFar, depth );","} else {","const float LOG2 = 1.442695;","float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );","fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );","}","gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );","}","}"].join("\n")),c.compileShader(b),c.compileShader(e),c.attachShader(a,b),c.attachShader(a,e),c.linkProgram(a),a}function b(a,b){return a.z!==b.z?b.z-a.z:b.id-a.id}var c,d,f,g,h,i,j,k,l,m;this.init=function(b){c=b.context,d=b,g=new Float32Array([-.5,-.5,0,0,.5,-.5,1,0,.5,.5,1,1,-.5,.5,0,1]),h=new Uint16Array([0,1,2,0,2,3]),i=c.createBuffer(),j=c.createBuffer(),c.bindBuffer(c.ARRAY_BUFFER,i),c.bufferData(c.ARRAY_BUFFER,g,c.STATIC_DRAW),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,j),c.bufferData(c.ELEMENT_ARRAY_BUFFER,h,c.STATIC_DRAW),k=a(),l={position:c.getAttribLocation(k,"position"),uv:c.getAttribLocation(k,"uv")},m={uvOffset:c.getUniformLocation(k,"uvOffset"),uvScale:c.getUniformLocation(k,"uvScale"),rotation:c.getUniformLocation(k,"rotation"),scale:c.getUniformLocation(k,"scale"),color:c.getUniformLocation(k,"color"),map:c.getUniformLocation(k,"map"),opacity:c.getUniformLocation(k,"opacity"),modelViewMatrix:c.getUniformLocation(k,"modelViewMatrix"),projectionMatrix:c.getUniformLocation(k,"projectionMatrix"),fogType:c.getUniformLocation(k,"fogType"),fogDensity:c.getUniformLocation(k,"fogDensity"),fogNear:c.getUniformLocation(k,"fogNear"),fogFar:c.getUniformLocation(k,"fogFar"),fogColor:c.getUniformLocation(k,"fogColor"),alphaTest:c.getUniformLocation(k,"alphaTest")};var n=document.createElement("canvas");n.width=8,n.height=8;var o=n.getContext("2d");o.fillStyle="#ffffff",o.fillRect(0,0,n.width,n.height),f=new e.Texture(n),f.needsUpdate=!0},this.render=function(a,g,h,n){var o=a.__webglSprites,p=o.length;if(p){c.useProgram(k),c.enableVertexAttribArray(l.position),c.enableVertexAttribArray(l.uv),c.disable(c.CULL_FACE),c.enable(c.BLEND),c.bindBuffer(c.ARRAY_BUFFER,i),c.vertexAttribPointer(l.position,2,c.FLOAT,!1,16,0),c.vertexAttribPointer(l.uv,2,c.FLOAT,!1,16,8),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,j),c.uniformMatrix4fv(m.projectionMatrix,!1,g.projectionMatrix.elements),c.activeTexture(c.TEXTURE0),c.uniform1i(m.map,0);var q=0,r=0,s=a.fog;s?(c.uniform3f(m.fogColor,s.color.r,s.color.g,s.color.b),s instanceof e.Fog?(c.uniform1f(m.fogNear,s.near),c.uniform1f(m.fogFar,s.far),c.uniform1i(m.fogType,1),q=1,r=1):s instanceof e.FogExp2&&(c.uniform1f(m.fogDensity,s.density),c.uniform1i(m.fogType,2),q=2,r=2)):(c.uniform1i(m.fogType,0),q=0,r=0);var t,u,v,w,x=[];for(t=0;p>t;t++)u=o[t],v=u.material,u.visible!==!1&&(u._modelViewMatrix.multiplyMatrices(g.matrixWorldInverse,u.matrixWorld),u.z=-u._modelViewMatrix.elements[14]);for(o.sort(b),t=0;p>t;t++)u=o[t],u.visible!==!1&&(v=u.material,c.uniform1f(m.alphaTest,v.alphaTest),c.uniformMatrix4fv(m.modelViewMatrix,!1,u._modelViewMatrix.elements),x[0]=u.scale.x,x[1]=u.scale.y,w=a.fog&&v.fog?r:0,q!==w&&(c.uniform1i(m.fogType,w),q=w),null!==v.map?(c.uniform2f(m.uvOffset,v.map.offset.x,v.map.offset.y),c.uniform2f(m.uvScale,v.map.repeat.x,v.map.repeat.y)):(c.uniform2f(m.uvOffset,0,0),c.uniform2f(m.uvScale,1,1)),c.uniform1f(m.opacity,v.opacity),c.uniform3f(m.color,v.color.r,v.color.g,v.color.b),c.uniform1f(m.rotation,v.rotation),c.uniform2fv(m.scale,x),d.setBlending(v.blending,v.blendEquation,v.blendSrc,v.blendDst),d.setDepthTest(v.depthTest),d.setDepthWrite(v.depthWrite),v.map&&v.map.image&&v.map.image.width?d.setTexture(v.map,0):d.setTexture(f,0),c.drawElements(c.TRIANGLES,6,c.UNSIGNED_SHORT,0));c.enable(c.CULL_FACE)}}},e.DepthPassPlugin=function(){function a(a){return a.material instanceof e.MeshFaceMaterial?a.material.materials[0]:a.material}this.enabled=!1,this.renderTarget=null;var b,c,d,f,g,h,i=new e.Frustum,j=new e.Matrix4;this.init=function(a){b=a.context,c=a;var i=e.ShaderLib.depthRGBA,j=e.UniformsUtils.clone(i.uniforms);d=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j}),f=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j,morphTargets:!0}),g=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j,skinning:!0}),h=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j,morphTargets:!0,skinning:!0}),d._shadowPass=!0,f._shadowPass=!0,g._shadowPass=!0,h._shadowPass=!0},this.render=function(a,b){this.enabled&&this.update(a,b)},this.update=function(k,l){var m,n,o,p,q,r,s,t=null;for(b.clearColor(1,1,1,1),b.disable(b.BLEND),c.setDepthTest(!0),k.autoUpdate===!0&&k.updateMatrixWorld(),l.matrixWorldInverse.getInverse(l.matrixWorld),j.multiplyMatrices(l.projectionMatrix,l.matrixWorldInverse),i.setFromMatrix(j),c.setRenderTarget(this.renderTarget),c.clear(),s=k.__webglObjects,m=0,n=s.length;n>m;m++)q=s[m],r=q.object,q.render=!1,r.visible&&((r instanceof e.Mesh||r instanceof e.ParticleSystem)&&r.frustumCulled&&!i.intersectsObject(r)||(r._modelViewMatrix.multiplyMatrices(l.matrixWorldInverse,r.matrixWorld),q.render=!0));var u,v,w;for(m=0,n=s.length;n>m;m++)if(q=s[m],q.render){if(r=q.object,o=q.buffer,r instanceof e.ParticleSystem&&!r.customDepthMaterial)continue;u=a(r),u&&c.setMaterialFaces(r.material),v=r.geometry.morphTargets.length>0&&u.morphTargets,w=r instanceof e.SkinnedMesh&&u.skinning,p=r.customDepthMaterial?r.customDepthMaterial:w?v?h:g:v?f:d,o instanceof e.BufferGeometry?c.renderBufferDirect(l,k.__lights,t,p,o,r):c.renderBuffer(l,k.__lights,t,p,o,r)}for(s=k.__webglObjectsImmediate,m=0,n=s.length;n>m;m++)q=s[m],r=q.object,r.visible&&(r._modelViewMatrix.multiplyMatrices(l.matrixWorldInverse,r.matrixWorld),c.renderImmediateObject(l,k.__lights,t,d,r));var x=c.getClearColor(),y=c.getClearAlpha();b.clearColor(x.r,x.g,x.b,y),b.enable(b.BLEND)}},e.ShaderFlares={lensFlareVertexTexture:{vertexShader:["uniform lowp int renderType;","uniform vec3 screenPosition;","uniform vec2 scale;","uniform float rotation;","uniform sampler2D occlusionMap;","attribute vec2 position;","attribute vec2 uv;","varying vec2 vUV;","varying float vVisibility;","void main() {","vUV = uv;","vec2 pos = position;","if( renderType == 2 ) {","vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );","visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );","visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );","visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );","visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );","visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );","visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );","visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );","visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );","vVisibility = visibility.r / 9.0;","vVisibility *= 1.0 - visibility.g / 9.0;","vVisibility *= visibility.b / 9.0;","vVisibility *= 1.0 - visibility.a / 9.0;","pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;","pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;","}","gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );","}"].join("\n"),fragmentShader:["uniform lowp int renderType;","uniform sampler2D map;","uniform float opacity;","uniform vec3 color;","varying vec2 vUV;","varying float vVisibility;","void main() {","if( renderType == 0 ) {","gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );","} else if( renderType == 1 ) {","gl_FragColor = texture2D( map, vUV );","} else {","vec4 texture = texture2D( map, vUV );","texture.a *= opacity * vVisibility;","gl_FragColor = texture;","gl_FragColor.rgb *= color;","}","}"].join("\n")},lensFlare:{vertexShader:["uniform lowp int renderType;","uniform vec3 screenPosition;","uniform vec2 scale;","uniform float rotation;","attribute vec2 position;","attribute vec2 uv;","varying vec2 vUV;","void main() {","vUV = uv;","vec2 pos = position;","if( renderType == 2 ) {","pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;","pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;","}","gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );","}"].join("\n"),fragmentShader:["precision mediump float;","uniform lowp int renderType;","uniform sampler2D map;","uniform sampler2D occlusionMap;","uniform float opacity;","uniform vec3 color;","varying vec2 vUV;","void main() {","if( renderType == 0 ) {","gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );","} else if( renderType == 1 ) {","gl_FragColor = texture2D( map, vUV );","} else {","float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;","visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;","visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;","visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;","visibility = ( 1.0 - visibility / 4.0 );","vec4 texture = texture2D( map, vUV );","texture.a *= opacity * visibility;","gl_FragColor = texture;","gl_FragColor.rgb *= color;","}","}"].join("\n")}},"undefined"!=typeof c?("undefined"!=typeof b&&b.exports&&(c=b.exports=e),c.THREE=e):this.THREE=e},{}],13:[function(a,b,c){void 0===Date.now&&(Date.now=function(){return(new Date).valueOf()});var d=d||function(){var a=[];return{REVISION:"13",getAll:function(){return a},removeAll:function(){a=[]},add:function(b){a.push(b)},remove:function(b){var c=a.indexOf(b);-1!==c&&a.splice(c,1)},update:function(b){if(0===a.length)return!1;var c=0;for(b=void 0!==b?b:"undefined"!=typeof window&&void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now();ca;a++)p[a].stop()},this.delay=function(a){return l=a,this},this.repeat=function(a){return h=a,this},this.yoyo=function(a){return i=a,this},this.easing=function(a){return n=a,this},this.interpolation=function(a){return o=a,this},this.chain=function(){return p=arguments,this},this.onStart=function(a){return q=a,this},this.onUpdate=function(a){return s=a,this},this.onComplete=function(a){return t=a,this},this.onStop=function(a){return u=a,this},this.update=function(a){var d;if(m>a)return!0;r===!1&&(null!==q&&q.call(b),r=!0);var j=(a-m)/g;j=j>1?1:j;var u=n(j);for(d in e){var v=c[d]||0,w=e[d];w instanceof Array?b[d]=o(w,u):("string"==typeof w&&(w=v+parseFloat(w,10)),"number"==typeof w&&(b[d]=v+(w-v)*u))}if(null!==s&&s.call(b,u),1==j){if(h>0){isFinite(h)&&h--;for(d in f){if("string"==typeof e[d]&&(f[d]=f[d]+parseFloat(e[d],10)),i){var x=f[d];f[d]=e[d],e[d]=x}c[d]=f[d]}return i&&(k=!k),m=a+l,!0}null!==t&&t.call(b);for(var y=0,z=p.length;z>y;y++)p[y].start(a);return!1}return!0}},d.Easing={Linear:{None:function(a){return a}},Quadratic:{In:function(a){return a*a},Out:function(a){return a*(2-a)},InOut:function(a){return(a*=2)<1?.5*a*a:-.5*(--a*(a-2)-1)}},Cubic:{In:function(a){return a*a*a},Out:function(a){return--a*a*a+1},InOut:function(a){return(a*=2)<1?.5*a*a*a:.5*((a-=2)*a*a+2)}},Quartic:{In:function(a){return a*a*a*a},Out:function(a){return 1- --a*a*a*a},InOut:function(a){return(a*=2)<1?.5*a*a*a*a:-.5*((a-=2)*a*a*a-2)}},Quintic:{In:function(a){return a*a*a*a*a},Out:function(a){return--a*a*a*a*a+1},InOut:function(a){return(a*=2)<1?.5*a*a*a*a*a:.5*((a-=2)*a*a*a*a+2)}},Sinusoidal:{In:function(a){return 1-Math.cos(a*Math.PI/2)},Out:function(a){return Math.sin(a*Math.PI/2)},InOut:function(a){return.5*(1-Math.cos(Math.PI*a))}},Exponential:{In:function(a){return 0===a?0:Math.pow(1024,a-1)},Out:function(a){return 1===a?1:1-Math.pow(2,-10*a)},InOut:function(a){return 0===a?0:1===a?1:(a*=2)<1?.5*Math.pow(1024,a-1):.5*(-Math.pow(2,-10*(a-1))+2)}},Circular:{In:function(a){return 1-Math.sqrt(1-a*a)},Out:function(a){return Math.sqrt(1- --a*a)},InOut:function(a){return(a*=2)<1?-.5*(Math.sqrt(1-a*a)-1):.5*(Math.sqrt(1-(a-=2)*a)+1)}},Elastic:{In:function(a){var b,c=.1,d=.4;return 0===a?0:1===a?1:(!c||1>c?(c=1,b=d/4):b=d*Math.asin(1/c)/(2*Math.PI),-(c*Math.pow(2,10*(a-=1))*Math.sin((a-b)*(2*Math.PI)/d)))},Out:function(a){var b,c=.1,d=.4;return 0===a?0:1===a?1:(!c||1>c?(c=1,b=d/4):b=d*Math.asin(1/c)/(2*Math.PI),c*Math.pow(2,-10*a)*Math.sin((a-b)*(2*Math.PI)/d)+1)},InOut:function(a){var b,c=.1,d=.4;return 0===a?0:1===a?1:(!c||1>c?(c=1,b=d/4):b=d*Math.asin(1/c)/(2*Math.PI),(a*=2)<1?-.5*(c*Math.pow(2,10*(a-=1))*Math.sin((a-b)*(2*Math.PI)/d)):c*Math.pow(2,-10*(a-=1))*Math.sin((a-b)*(2*Math.PI)/d)*.5+1)}},Back:{In:function(a){var b=1.70158;return a*a*((b+1)*a-b)},Out:function(a){var b=1.70158;return--a*a*((b+1)*a+b)+1},InOut:function(a){var b=2.5949095;return(a*=2)<1?.5*(a*a*((b+1)*a-b)):.5*((a-=2)*a*((b+1)*a+b)+2)}},Bounce:{In:function(a){return 1-d.Easing.Bounce.Out(1-a)},Out:function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375},InOut:function(a){return.5>a?.5*d.Easing.Bounce.In(2*a):.5*d.Easing.Bounce.Out(2*a-1)+.5}}},d.Interpolation={Linear:function(a,b){var c=a.length-1,e=c*b,f=Math.floor(e),g=d.Interpolation.Utils.Linear;return 0>b?g(a[0],a[1],e):b>1?g(a[c],a[c-1],c-e):g(a[f],a[f+1>c?c:f+1],e-f)},Bezier:function(a,b){var c,e=0,f=a.length-1,g=Math.pow,h=d.Interpolation.Utils.Bernstein;for(c=0;f>=c;c++)e+=g(1-b,f-c)*g(b,c)*a[c]*h(f,c);return e},CatmullRom:function(a,b){var c=a.length-1,e=c*b,f=Math.floor(e),g=d.Interpolation.Utils.CatmullRom;return a[0]===a[c]?(0>b&&(f=Math.floor(e=c*(1+b))),g(a[(f-1+c)%c],a[f],a[(f+1)%c],a[(f+2)%c],e-f)):0>b?a[0]-(g(a[0],a[0],a[1],a[1],-e)-a[0]):b>1?a[c]-(g(a[c],a[c],a[c-1],a[c-1],e-c)-a[c]):g(a[f?f-1:0],a[f],a[f+1>c?c:f+1],a[f+2>c?c:f+2],e-f)},Utils:{Linear:function(a,b,c){return(b-a)*c+a},Bernstein:function(a,b){var c=d.Interpolation.Utils.Factorial;return c(a)/c(b)/c(a-b)},Factorial:function(){var a=[1];return function(b){var c,d=1;if(a[b])return a[b];for(c=b;c>1;c--)d*=c;return a[b]=d}}(),CatmullRom:function(a,b,c,d,e){var f=.5*(c-a),g=.5*(d-b),h=e*e,i=e*h;return(2*b-2*c+f+g)*i+(-3*b+3*c-2*f-g)*h+f*e+b}}},b.exports=d},{}],14:[function(a,b,c){!function d(a,c,e){function f(a,b){return this instanceof f?(g(a)?(b=a[1],a=a[0]):"object"==typeof a&&a&&(b=a.y,a=a.x),this.x=f.clean(a||0),void(this.y=f.clean(b||0))):new f(a,b)}var g=function(a){return"[object Array]"===Object.prototype.toString.call(a)};f.prototype={change:function(a){if("function"==typeof a)this.observers?this.observers.push(a):this.observers=[a];else if(this.observers&&this.observers.length)for(var b=this.observers.length-1;b>=0;b--)this.observers[b](this,a);return this},ignore:function(a){if(this.observers)if(a)for(var b=this.observers,c=b.length;c--;)b[c]===a&&b.splice(c,1);else this.observers=[];return this},set:function(a,b,c){if("number"!=typeof a&&(c=b,b=a.y,a=a.x),this.x===a&&this.y===b)return this;var d=null;return c!==!1&&this.observers&&this.observers.length&&(d=this.clone()),this.x=f.clean(a),this.y=f.clean(b),c!==!1?this.change(d):void 0; +},zero:function(){return this.set(0,0)},clone:function(){return new this.constructor(this.x,this.y)},negate:function(a){return a?new this.constructor(-this.x,-this.y):this.set(-this.x,-this.y)},add:function(a,b,c){return"number"!=typeof a&&(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)),a+=this.x,b+=this.y,c?new this.constructor(a,b):this.set(a,b)},subtract:function(a,b,c){return"number"!=typeof a&&(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)),a=this.x-a,b=this.y-b,c?new this.constructor(a,b):this.set(a,b)},multiply:function(a,b,c){return"number"!=typeof a?(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)):"number"!=typeof b&&(c=b,b=a),a*=this.x,b*=this.y,c?new this.constructor(a,b):this.set(a,b)},rotate:function(a,b,c){var d,e,f=this.x,g=this.y,h=Math.cos(a),i=Math.sin(a);return b=b?-1:1,d=h*f-b*i*g,e=b*i*f+h*g,c?new this.constructor(d,e):this.set(d,e)},length:function(){var a=this.x,b=this.y;return Math.sqrt(a*a+b*b)},lengthSquared:function(){var a=this.x,b=this.y;return a*a+b*b},distance:function(a){var b=this.x-a.x,c=this.y-a.y;return Math.sqrt(b*b+c*c)},normalize:function(a){var b=this.length(),c=bc?c:e,h=f>d?d:f;return b?new this.constructor(g,h):this.set(g,h)},max:function(a,b){var c=this.x,d=this.y,e=a.x,f=a.y,g=c>e?c:e,h=d>f?d:f;return b?new this.constructor(g,h):this.set(g,h)},clamp:function(a,b,c){var d=this.min(b,!0).max(a);return c?d:this.set(d.x,d.y)},lerp:function(a,b,c){return this.add(a.subtract(this,!0).multiply(b),c)},skew:function(a){return a?new this.constructor(-this.y,this.x):this.set(-this.y,this.x)},dot:function(a){return f.clean(this.x*a.x+a.y*this.y)},perpDot:function(a){return f.clean(this.x*a.y-this.y*a.x)},angleTo:function(a){return Math.atan2(this.perpDot(a),this.dot(a))},divide:function(a,b,c){if("number"!=typeof a?(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)):"number"!=typeof b&&(c=b,b=a),0===a||0===b)throw new Error("division by zero");if(isNaN(a)||isNaN(b))throw new Error("NaN detected");return c?new this.constructor(this.x/a,this.y/b):this.set(this.x/a,this.y/b)},isPointOnLine:function(a,b){return(a.y-this.y)*(a.x-b.x)===(a.y-b.y)*(a.x-this.x)},toArray:function(){return[this.x,this.y]},fromArray:function(a){return this.set(a[0],a[1])},toJSON:function(){return{x:this.x,y:this.y}},toString:function(){return"("+this.x+", "+this.y+")"},constructor:f},f.fromArray=function(a,b){return new(b||f)(a[0],a[1])},f.precision=c||8;var h=Math.pow(10,f.precision);return f.clean=a||function(a){if(isNaN(a))throw new Error("NaN detected");if(!isFinite(a))throw new Error("Infinity detected");return Math.round(a)===a?a:Math.round(a*h)/h},f.inject=d,a||(f.fast=d(function(a){return a}),"undefined"!=typeof b&&"object"==typeof b.exports?b.exports=f:window.Vec2=window.Vec2||f),f}()},{}],15:[function(a,b,c){function d(a,b,c){c||(c={}),this.width=a,this.height=b,this.points=[],this.introLines=new f.Object3D,this.pins=[],this.markers=[],this.satelliteAnimations=[],this.satelliteMeshes=[],this.satellites={},this.quadtree=new g(new h(180,360),5),this.active=!0;var d={font:"Inconsolata",baseColor:"#ffcc00",markerColor:"#ffcc00",pinColor:"#00eeee",satelliteColor:"#ff0000",introLinesAltitude:1.1,introLinesDuration:2e3,introLinesColor:"#8FD8D8",introLinesCount:60,scale:1,dayLength:28e3,maxPins:500,maxMarkers:4,data:[],tiles:[],viewAngle:.1,cameraAngle:Math.PI};for(var e in d)this[e]||(this[e]=d[e],void 0!==c[e]&&(this[e]=c[e]));0===this.dayLength?this.rotationSpeed=0:this.rotationSpeed=1e3/this.dayLength,this.setScale(this.scale),this.renderer=new f.WebGLRenderer({antialias:!0}),this.renderer.setSize(this.width,this.height),this.renderer.gammaInput=!0,this.renderer.gammaOutput=!0,this.domElement=this.renderer.domElement,this.data.sort(function(a,b){return b.lng-2*b.label.length-(a.lng-2*a.label.length)});for(var e=0;e0&&this.firstRunTime+(next=this.data.pop()).when=Date.now()&&this.data.push(next)}},q=function(){this.hexGrid&&this.scene.remove(this.hexGrid);var a=["#define PI 3.141592653589793238462643","#define DISTANCE 500.0","#define INTRODURATION "+(parseFloat(this.introLinesDuration)+1e-5),"#define INTROALTITUDE "+(parseFloat(this.introLinesAltitude)+1e-5),"attribute float lng;","uniform float currentTime;","varying vec4 vColor;","","void main()","{"," vec3 newPos = position;"," float opacityVal = 0.0;"," float introStart = INTRODURATION * ((180.0 + lng)/360.0);"," if(currentTime > introStart){"," opacityVal = 1.0;"," }"," if(currentTime > introStart && currentTime < introStart + INTRODURATION / 8.0){"," newPos = position * INTROALTITUDE;"," opacityVal = .3;"," }"," if(currentTime > introStart + INTRODURATION / 8.0 && currentTime < introStart + INTRODURATION / 8.0 + 200.0){"," newPos = position * (1.0 + ((INTROALTITUDE-1.0) * (1.0-(currentTime - introStart-(INTRODURATION/8.0))/200.0)));"," }"," vColor = vec4( color, opacityVal );"," gl_Position = projectionMatrix * modelViewMatrix * vec4(newPos, 1.0);","}"].join("\n"),b=["varying vec4 vColor;","void main()","{"," gl_FragColor = vColor;"," float depth = gl_FragCoord.z / gl_FragCoord.w;"," float fogFactor = smoothstep("+parseInt(this.cameraDistance)+".0,"+parseInt(this.cameraDistance+300)+".0, depth );"," vec3 fogColor = vec3(0.0);"," gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w ), fogFactor );","}"].join("\n"),c={lng:{type:"f",value:null}};this.pointUniforms={currentTime:{type:"f",value:0}};var d=new f.ShaderMaterial({uniforms:this.pointUniforms,attributes:c,vertexShader:a,fragmentShader:b,transparent:!0,vertexColors:f.VertexColors,side:f.DoubleSide}),e=4*this.tiles.length,g=new f.BufferGeometry;g.addAttribute("index",Uint16Array,3*e,1),g.addAttribute("position",Float32Array,3*e,3),g.addAttribute("normal",Float32Array,3*e,3),g.addAttribute("color",Float32Array,3*e,3),g.addAttribute("lng",Float32Array,3*e,1);for(var h=g.attributes.lng.array,i=m(this.baseColor).hueSet(),j=[],k=0;k5&&q(s+3,r.b[0].x,r.b[0].y,r.b[0].z,r.b[5].x,r.b[5].y,r.b[5].z,r.b[4].x,r.b[4].y,r.b[4].z,r.lat,r.lon,v)}g.offsets=[];for(var w=e/l,k=0;w>k;k++){var x={start:k*l*3,index:k*l*3,count:3*Math.min(e-k*l,l)};g.offsets.push(x)}g.computeBoundingSphere(),this.hexGrid=new f.Mesh(g,d),this.scene.add(this.hexGrid)},r=function(){for(var a,b=new f.LineBasicMaterial({color:this.introLinesColor,transparent:!0,linewidth:2,opacity:.5}),c=0;ci;i++){var j=n.mapPoint(e,g-5*i);a=new f.Vector3(j.x*this.introLinesAltitude,j.y*this.introLinesAltitude,j.z*this.introLinesAltitude),d.vertices.push(a)}this.introLines.add(new f.Line(d,b))}this.scene.add(this.introLines)},s=function(a){var b,c=!1,d=0,e=Date.now(),g=!1,h=new f.Vector3(0,0,0),i=new f.Projector;a.domElement.onmousedown=function(a){c=!0,d=a.clientX,e=Date.now(),g=!1},a.domElement.onmouseup=function(b){c=!1,a.resetRotationSpeed()},a.domElement.onmouseleave=function(b){c=!1,a.resetRotationSpeed()};var j=function(f,i){h.x=2*(f.clientX/a.width)-1,h.y=1-2*(f.clientY/a.height);var k=Date.now()-e;c&&k&&(g=!0,a.setRotationSpeed((f.clientX-d)/a.width/(k/1e3)),e=Date.now(),d=f.clientX,clearTimeout(b),i||(b=setTimeout(function(){j(f,!0)},100)))},k=function(b){if(!g){for(var c=i.pickingRay(h.clone(),a.camera),d=c.intersectObjects(a.scene.children),e=1.1*a.cameraDistance,f=null,j=0;j0)){var k=a.camera.position.distanceTo(d[j].object.position);e>k&&(e=k,f=objName)}null!=f&&a.clickHandler&&a.clickHandler(f)}};a.domElement.onmousemove=j,a.domElement.onclick=k};d.prototype.init=function(a){this.camera=new f.PerspectiveCamera(50,this.width/this.height,1,this.cameraDistance+300),this.camera.position.z=this.cameraDistance,this.scene=new f.Scene,this.scene.fog=new f.Fog(0,this.cameraDistance,this.cameraDistance+300),r.call(this),this.smokeProvider=new l(this.scene),q.call(this),setTimeout(a,500)},d.prototype.destroy=function(a){var b=this;this.active=!1,setTimeout(function(){for(;b.scene.children.length>0;)b.scene.remove(b.scene.children[0]);"function"==typeof a&&a()},1e3)},d.prototype.addPin=function(a,b,c,d){a=parseFloat(a),b=parseFloat(b);var e={lineColor:this.pinColor,topColor:this.pinColor,font:this.font,id:d},f=1.2;"string"==typeof c&&0!==c.length||(f-=.05+.05*Math.random());var g=new i(a,b,c,f,this.scene,this.smokeProvider,e);this.pins.push(g);var j=o(a,b);if(g.pos_=new h(parseInt(j.x),parseInt(j.y)),c.length>0?g.rad_=j.rad:g.rad_=1,this.quadtree.addObject(g),c.length>0){var k=this.quadtree.getCollisionsForObject(g),l=0,m=0,n=[];for(var p in k)k[p].text.length>0&&(l++,k[p].age()>5e3?n.push(k[p]):m++);if(l>0&&0==m)for(var p=0;p0&&(g.hideLabel(),g.hideSmoke(),g.hideTop(),g.changeAltitude(.05*Math.random()+1.1))}if(this.pins.length>this.maxPins){var q=this.pins.shift();this.quadtree.removeObject(q),q.remove()}return g},d.prototype.addMarker=function(a,b,c,d){var e,f={markerColor:this.markerColor,lineColor:this.markerColor,font:this.font};return e="boolean"==typeof d&&d?new j(a,b,c,1.2,this.markers[this.markers.length-1],this.scene,f):"object"==typeof d?new j(a,b,c,1.2,d,this.scene,f):new j(a,b,c,1.2,null,this.scene,f),this.markers.push(e),this.markers.length>this.maxMarkers&&this.markers.shift().remove(),e},d.prototype.addSatellite=function(a,b,c,d,e,f){d||(d={}),void 0==d.coreColor&&(d.coreColor=this.satelliteColor);var g=new k(a,b,c,this.scene,d,e,f);return this.satellites[g.toString()]||(this.satellites[g.toString()]=g),g.onRemove(function(){delete this.satellites[g.toString()]}.bind(this)),g},d.prototype.addConstellation=function(a,b){for(var c,d=[],e=0;ethis.maxPins;){var b=this.pins.shift();this.quadtree.removeObject(b),b.remove()}},d.prototype.setMaxMarkers=function(a){for(this.maxMarkers=a;this.markers.length>this.maxMarkers;)this.markers.shift().remove()},d.prototype.setBaseColor=function(a){this.baseColor=a,q.call(this)},d.prototype.setMarkerColor=function(a){this.markerColor=a,this.scene._encom_markerTexture=null},d.prototype.setPinColor=function(a){this.pinColor=a},d.prototype.setScale=function(a){this.scale=a,this.cameraDistance=1700/a,this.scene&&this.scene.fog&&(this.scene.fog.near=this.cameraDistance,this.scene.fog.far=this.cameraDistance+300,q.call(this),this.camera.far=this.cameraDistance+300,this.camera.updateProjectionMatrix())},d.prototype.setRotationSpeed=function(a){this.rotationSpeed=a},d.prototype.resetRotationSpeed=function(){this.rotationSpeed=this.defaultRotationSpeed},d.prototype.tick=function(){if(this.camera){this.firstRunTime||(this.firstRunTime=Date.now()),p.call(this),e.update(),this.lastRenderDate||(this.lastRenderDate=new Date),this.firstRenderDate||(this.firstRenderDate=new Date),this.totalRunTime=new Date-this.firstRenderDate;var a=new Date-this.lastRenderDate;this.lastRenderDate=new Date;var b=this.rotationSpeed*a/1e3*2*Math.PI;this.cameraAngle+=b,this.active||(this.cameraDistance+=1e3*a/1e3),this.camera.position.x=this.cameraDistance*Math.cos(this.cameraAngle)*Math.cos(this.viewAngle),this.camera.position.y=Math.sin(this.viewAngle)*this.cameraDistance,this.camera.position.z=this.cameraDistance*Math.sin(this.cameraAngle)*Math.cos(this.viewAngle);for(var c in this.satellites)this.satellites[c].tick(this.camera.position,this.cameraAngle,a);for(var c=0;cthis.totalRunTime?(this.totalRunTime/this.introLinesDuration<.1&&(this.introLines.children[0].material.opacity=this.totalRunTime/this.introLinesDuration*10-.2),this.totalRunTime/this.introLinesDuration>.8?this.introLines.children[0].material.opacity=5*Math.max(1-this.totalRunTime/this.introLinesDuration,0):this.introLines.children[0].material.opacity=1,this.introLines.rotateY(2*Math.PI/(this.introLinesDuration/a))):this.introLines&&(this.scene.remove(this.introLines),delete[this.introLines]),this.pointUniforms.currentTime.value=this.totalRunTime,this.smokeProvider.tick(this.totalRunTime),this.camera.lookAt(this.scene.position),this.renderer.render(this.scene,this.camera)}},d.prototype.setClickHandler=function(a){this.clickHandler=a},b.exports=d},{"./Marker":16,"./Pin":17,"./Satellite":18,"./SmokeProvider":19,"./utils":21,"hexasphere.js":3,"pusher.color":6,quadtree2:8,three:12,"tween.js":13,vec2:14}],16:[function(a,b,c){var d=a("three"),e=a("tween.js"),f=a("./utils"),g=function(a){var b,c,e=30,g=30;return b=f.renderToCanvas(e,g,function(b){b.fillStyle=a,b.strokeStyle=a,b.lineWidth=3,b.beginPath(),b.arc(e/2,g/2,e/3,0,2*Math.PI),b.stroke(),b.beginPath(),b.arc(e/2,g/2,e/5,0,2*Math.PI),b.fill()}),c=new d.Texture(b),c.needsUpdate=!0,c},h=function(a,b,c,h,i,j,k){var l,m,n,o,p,q,r={lineColor:"#FFCC00",lineWidth:1,markerColor:"#FFCC00",labelColor:"#FFF",font:"Inconsolata",fontSize:20,drawTime:2e3,lineSegments:150};if(this.lat=parseFloat(a),this.lon=parseFloat(b),this.text=c,this.altitude=parseFloat(h),this.scene=j,this.previous=i,this.next=[],this.previous&&this.previous.next.push(this),k)for(var s in r)void 0!=k[s]&&(r[s]=k[s]);this.opts=r,l=f.mapPoint(a,b),i&&(m=f.mapPoint(i.lat,i.lon)),j._encom_markerTexture||(j._encom_markerTexture=g(this.opts.markerColor)),n=new d.SpriteMaterial({map:j._encom_markerTexture,opacity:.7,depthTest:!0,fog:!0}),this.marker=new d.Sprite(n),this.marker.scale.set(0,0),this.marker.position.set(l.x*h,l.y*h,l.z*h),o=f.createLabel(c.toUpperCase(),this.opts.fontSize,this.opts.labelColor,this.opts.font,this.opts.markerColor),p=new d.Texture(o),p.needsUpdate=!0,q=new d.SpriteMaterial({map:p,useScreenCoordinates:!1,opacity:0,depthTest:!0,fog:!0}),this.labelSprite=new d.Sprite(q),this.labelSprite.position={x:l.x*h*1.1,y:l.y*h*1.05+(l.y<0?-15:30),z:l.z*h*1.1},this.labelSprite.scale.set(o.width,o.height),new e.Tween({opacity:0}).to({opacity:1},500).onUpdate(function(){q.opacity=this.opacity}).start();var t=this;if(new e.Tween({x:0,y:0}).to({x:50,y:50},2e3).easing(e.Easing.Elastic.Out).onUpdate(function(){t.marker.scale.set(this.x,this.y)}).delay(this.previous?t.opts.drawTime:0).start(),this.previous){var u,v,w,x,y,z,A,B,C,D,E,F,G=[],H=[];t.geometrySpline=new d.Geometry,u=new d.LineBasicMaterial({color:this.opts.lineColor,transparent:!0,linewidth:3,opacity:.5}),t.geometrySplineDotted=new d.Geometry,v=new d.LineBasicMaterial({color:this.opts.lineColor,linewidth:1,transparent:!0,opacity:.5}),w=(a-i.lat)/t.opts.lineSegments,x=(b-i.lon)/t.opts.lineSegments,y=f.mapPoint(i.lat,i.lon),G=[],H=[];for(var I=0;I=a.index&&(E.set(1.2*D.x,1.2*D.y,1.2*D.z),currentVert2.set(1.19*currentPoint2.x,1.19*currentPoint2.y,1.19*currentPoint2.z)),t.geometrySpline.verticesNeedUpdate=!0,t.geometrySplineDotted.verticesNeedUpdate=!0;G.length>0&&setTimeout(F,t.opts.drawTime/t.opts.lineSegments)},F(),this.scene.add(new d.Line(t.geometrySpline,u)),this.scene.add(new d.Line(t.geometrySplineDotted,v,d.LinePieces))}this.scene.add(this.marker),this.scene.add(this.labelSprite)};h.prototype.remove=function(){for(var a=0,b=this,c=function(d){for(var e=0;a>e;e++)d.geometrySpline.vertices[e].set(d.geometrySpline.vertices[e+1]),d.geometrySplineDotted.vertices[e].set(d.geometrySplineDotted.vertices[e+1]),d.geometrySpline.verticesNeedUpdate=!0,d.geometrySplineDotted.verticesNeedUpdate=!0;a++,a0,showTop:c.length>0,showSmoke:c.length>0,id:null};if(this.lat=a,this.lon=b,this.text=c,this.altitude=h,this.scene=i,this.smokeProvider=j,this.dateCreated=Date.now(),k)for(var t in s)void 0!=k[t]&&(s[t]=k[t]);this.opts=s,this.topVisible=s.showTop,this.smokeVisible=s.showSmoke,this.labelVisible=s.showLabel,this.lineGeometry=new d.Geometry,l=new d.LineBasicMaterial({color:s.lineColor,linewidth:s.lineWidth}),r=f.mapPoint(a,b),this.lineGeometry.vertices.push(new d.Vector3(r.x,r.y,r.z)),this.lineGeometry.vertices.push(new d.Vector3(r.x,r.y,r.z)),this.line=new d.Line(this.lineGeometry,l),m=f.createLabel(c,18,s.labelColor,s.font),n=new d.Texture(m),n.needsUpdate=!0,o=new d.SpriteMaterial({map:n,useScreenCoordinates:!1,opacity:0,depthTest:!0,fog:!0}),this.labelSprite=new d.Sprite(o),this.labelSprite.position={x:r.x*h*1.1,y:r.y*h+(r.y<0?-15:30),z:r.z*h*1.1},this.labelSprite.scale.set(m.width,m.height),p=new d.Texture(g(s.topColor)),p.needsUpdate=!0,q=new d.SpriteMaterial({map:p,depthTest:!0,fog:!0,opacity:0}),this.topSprite=new d.Sprite(q),this.topSprite.scale.set(20,20),this.topSprite.position.set(r.x*h,r.y*h,r.z*h),this.smokeVisible&&(this.smokeId=j.setFire(a,b,h));var u=this;(s.showTop||s.showLabel)&&new e.Tween({opacity:0}).to({opacity:1},500).onUpdate(function(){u.topVisible?q.opacity=this.opacity:q.opacity=0,u.labelVisible?o.opacity=this.opacity:o.opacity=0}).delay(1e3).start(),new e.Tween(r).to({x:r.x*h,y:r.y*h,z:r.z*h},1500).easing(e.Easing.Elastic.Out).onUpdate(function(){u.lineGeometry.vertices[1].x=this.x,u.lineGeometry.vertices[1].y=this.y,u.lineGeometry.vertices[1].z=this.z,u.lineGeometry.verticesNeedUpdate=!0}).start(),null!==this.opts.id&&void 0!==this.opts.id&&(this.labelSprite.name=this.opts.id,this.line.name=this.opts.id,this.topSprite.name=this.opts.id),this.scene.add(this.labelSprite),this.scene.add(this.line),this.scene.add(this.topSprite)};h.prototype.toString=function(){return""+this.lat+"_"+this.lon},h.prototype.changeAltitude=function(a){var b=f.mapPoint(this.lat,this.lon),c=this;new e.Tween({altitude:this.altitude}).to({altitude:a},1500).easing(e.Easing.Elastic.Out).onUpdate(function(){c.smokeVisible&&c.smokeProvider.changeAltitude(this.altitude,c.smokeId),c.topVisible&&c.topSprite.position.set(b.x*this.altitude,b.y*this.altitude,b.z*this.altitude),c.labelVisible&&(c.labelSprite.position={x:b.x*this.altitude*1.1,y:b.y*this.altitude+(b.y<0?-15:30),z:b.z*this.altitude*1.1}),c.lineGeometry.vertices[1].x=b.x*this.altitude,c.lineGeometry.vertices[1].y=b.y*this.altitude,c.lineGeometry.vertices[1].z=b.z*this.altitude,c.lineGeometry.verticesNeedUpdate=!0}).onComplete(function(){c.altitude=a}).start()},h.prototype.hideTop=function(){this.topVisible&&(this.topSprite.material.opacity=0,this.topVisible=!1)},h.prototype.showTop=function(){this.topVisible||(this.topSprite.material.opacity=1,this.topVisible=!0)},h.prototype.hideLabel=function(){this.labelVisible&&(this.labelSprite.material.opacity=0,this.labelVisible=!1)},h.prototype.showLabel=function(){this.labelVisible||(this.labelSprite.material.opacity=1,this.labelVisible=!0)},h.prototype.hideSmoke=function(){this.smokeVisible&&(this.smokeProvider.extinguish(this.smokeId),this.smokeVisible=!1)},h.prototype.showSmoke=function(){this.smokeVisible||(this.smokeId=this.smokeProvider.setFire(this.lat,this.lon,this.altitude),this.smokeVisible=!0)},h.prototype.age=function(){return Date.now()-this.dateCreated},h.prototype.remove=function(){this.scene.remove(this.labelSprite),this.scene.remove(this.line),this.scene.remove(this.topSprite),this.smokeVisible&&this.smokeProvider.extinguish(this.smokeId)},b.exports=h},{"./utils":21,three:12,"tween.js":13}],18:[function(a,b,c){var d=a("./TextureAnimator"),e=a("three"),f=a("./utils"),g=function(a,b,c,d,e,g,h,i){var j=a/c,k=Math.floor((a-d)/e),l=b-25,m=l/(a-d),n=0,o=0,p=0,q=f.hexToRgb(g);return f.renderToCanvas(a*b/c,b*c,function(c){for(var f=0;a>f;f++){f-p*j>=j&&(n=0,o+=b,p++);var g=n+25,l=o+Math.floor(b/2);c.lineWidth=2,c.strokeStyle=i;var r=Math.PI/16,s=-Math.PI+Math.PI/4,t=8,u=Math.floor(a-2*(a-d)/e)+1;d>f&&(t=t*f/d);for(var v=Math.floor((u-d)/2)+d,w=0;4>w;w++){if(c.beginPath(),d>f||f>=a)c.arc(g,l,t,w*Math.PI/2+s+r,w*Math.PI/2+s+Math.PI/2-2*r);else if(f>d&&v>f){var x=v-d,y=3*Math.PI/2,z=f-d,A=y/x,B=-Math.PI+Math.PI/4+r+A*z;c.arc(g,l,t,Math.max(w*Math.PI/2+s,B),Math.max(w*Math.PI/2+s+Math.PI/2-2*r,B+Math.PI/2-2*r))}else if(f>=v&&u>f){var x=u-v,y=2*w*Math.PI/4,z=f-v,A=y/x,B=Math.PI/2+Math.PI/4+r+A*z;c.arc(g,l,t,B,B+Math.PI/2-2*r)}else if(f>=u&&(a-u)/2+u>f){var x=(a-u)/2,y=Math.PI/2,z=f-u,A=y/x,B=w*(Math.PI/2)+Math.PI/4+r+A*z;c.arc(g,l,t,B,B+Math.PI/2-2*r)}else c.arc(g,l,t,w*Math.PI/2+s+r,w*Math.PI/2+s+Math.PI/2-2*r);c.stroke()}for(var C,D=0;e>D;D++)C=f-k*D-d,C>0&&b-25>C*m&&(c.strokeStyle="rgba("+q.r+","+q.g+","+q.b+","+(.9-C*m/(b-25))+")",c.lineWidth=2,c.beginPath(),c.arc(g,l,C*m,-Math.PI/12,Math.PI/12),c.stroke());c.fillStyle="#000",c.beginPath(),c.arc(g,l,3,0,2*Math.PI),c.fill(),c.strokeStyle=h,c.lineWidth=2,c.beginPath(),d>f?c.arc(g,l,3*f/d,0,2*Math.PI):c.arc(g,l,3,0,2*Math.PI),c.stroke(),n+=b}})},h=function(a,b,c,h,i,j,k){var l,m,n,o,p,q,r,s=f.mapPoint(a,b);s.x*=c,s.y*=c,s.z*=c;var m={numWaves:8,waveColor:"#FFF",coreColor:"#FF0000",shieldColor:"#FFF",size:1};if(this.lat=a,this.lon=b,this.altitude=c,this.scene=h,this.onRemoveList=[],n=50,o=100,p=10,q=Math.floor(n/8),i)for(var t in m)void 0!=i[t]&&(m[t]=i[t]);this.opts=m,j?(this.canvas=j,k?this.texture=k:(this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,r=Math.floor(n-2*(n-q)/m.numWaves)+1,this.animator=new d(this.texture,p,n/p,n,80,r))):(this.canvas=g(n,o,p,q,m.numWaves,m.waveColor,m.coreColor,m.shieldColor),this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,r=Math.floor(n-2*(n-q)/m.numWaves)+1,this.animator=new d(this.texture,p,n/p,n,80,r)),l=new e.PlaneGeometry(150*m.size,150*m.size,1,1),this.material=new e.MeshBasicMaterial({map:this.texture,depthTest:!1,transparent:!0}),this.mesh=new e.Mesh(l,this.material),this.mesh.tiltMultiplier=Math.PI/2*(1-Math.abs(a/90)),this.mesh.tiltDirection=a>0?-1:1,this.mesh.lon=b,this.mesh.position.set(s.x,s.y,s.z),this.mesh.rotation.z=-1*(a/90)*Math.PI/2,this.mesh.rotation.y=b/180*Math.PI,h.add(this.mesh)};h.prototype.changeAltitude=function(a){var b=f.mapPoint(this.lat,this.lon);b.x*=a,b.y*=a,b.z*=a,this.altitude=a,this.mesh.position.set(b.x,b.y,b.z)},h.prototype.changeCanvas=function(a,b,c,f){numFrames=50,pixels=100,rows=10,waveStart=Math.floor(numFrames/8),a?this.opts.numWaves=a:a=this.opts.numWaves,b?this.opts.waveColor=b:b=this.opts.waveColor,c?this.opts.coreColor=c:c=this.opts.coreColor,f?this.opts.shieldColor=f:f=this.opts.shieldColor,this.canvas=g(numFrames,pixels,rows,waveStart,a,b,c,f),this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,repeatAt=Math.floor(numFrames-2*(numFrames-waveStart)/a)+1,this.animator=new d(this.texture,rows,numFrames/rows,numFrames,80,repeatAt),this.material.map=this.texture},h.prototype.tick=function(a,b,c){this.mesh.lookAt(a),this.mesh.rotateZ(this.mesh.tiltDirection*Math.PI/2),this.mesh.rotateZ(Math.sin(b+this.mesh.lon/180*Math.PI)*this.mesh.tiltMultiplier*this.mesh.tiltDirection*-1),this.animator&&this.animator.update(c)},h.prototype.remove=function(){this.scene.remove(this.mesh);for(var a=0;a 0.0 && active > 0.0) {"," dt = mod(dt,1500.0);"," }"," float opacity = 1.0 - dt/ 1500.0;"," if (dt == 0.0 || active == 0.0){"," opacity = 0.0;"," }"," vec3 newPos = getPos(myStartLat, myStartLon - ( dt / 50.0));"," vColor = vec4( color, opacity );"," vec4 mvPosition = modelViewMatrix * vec4( newPos, 1.0 );"," gl_PointSize = 2.5 - (dt / 1500.0);"," gl_Position = projectionMatrix * mvPosition;","}"].join("\n"),g=["varying vec4 vColor;","void main()","{"," gl_FragColor = vColor;"," float depth = gl_FragCoord.z / gl_FragCoord.w;"," float fogFactor = smoothstep(1500.0, 1800.0, depth );"," vec3 fogColor = vec3(0.0);"," gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w), fogFactor );","}"].join("\n"),h=function(a,b){var c={smokeCount:5e3,smokePerPin:30,smokePerSecond:20};if(b)for(var e in c)void 0!==b[e]&&(c[e]=b[e]);this.opts=c,this.geometry=new d.Geometry,this.attributes={myStartTime:{type:"f",value:[]},myStartLat:{type:"f",value:[]},myStartLon:{type:"f",value:[]},altitude:{type:"f",value:[]},active:{type:"f",value:[]}},this.uniforms={currentTime:{type:"f",value:0},color:{type:"c",value:new d.Color("#aaa")}};for(var h=new d.ShaderMaterial({uniforms:this.uniforms,attributes:this.attributes,vertexShader:f,fragmentShader:g,transparent:!0}),e=0;ethis.tileDisplayDuration;)if(this.shutDownFlag&&this.currentTile>=e)this.done=!0,this.shutDownCb();else{this.currentDisplayTime-=this.tileDisplayDuration,this.currentTile++,this.currentTile!=e||this.shutDownFlag||(this.currentTile=g);var c=this.currentTile%this.tilesHorizontal;a.offset.x=c/this.tilesHorizontal;var d=Math.floor(this.currentTile/this.tilesHorizontal);a.offset.y=1-d/this.tilesVertical-1/this.tilesVertical}},this.shutDown=function(a){_this.shutDownFlag=!0,_this.shutDownCb=a}};b.exports=e},{three:12}],21:[function(a,b,c){var d={renderToCanvas:function(a,b,c){var d=document.createElement("canvas");return d.width=a,d.height=b,c(d.getContext("2d")),d},mapPoint:function(a,b,c){c||(c=500);var d=(90-a)*Math.PI/180,e=(180-b)*Math.PI/180,f=c*Math.sin(d)*Math.cos(e),g=c*Math.cos(d),h=c*Math.sin(d)*Math.sin(e); +return{x:f,y:g,z:h}},hexToRgb:function(a){var b=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;a=a.replace(b,function(a,b,c,d){return b+b+c+c+d+d});var c=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a);return c?{r:parseInt(c[1],16),g:parseInt(c[2],16),b:parseInt(c[3],16)}:null},createLabel:function(a,b,c,d,e){var f=document.createElement("canvas"),g=f.getContext("2d");g.font=b+"pt "+d;var h=g.measureText(a).width;return f.width=h,f.height=b+10,f.width%2&&f.width++,f.height%2&&f.height++,e&&(f.height+=30),g.font=b+"pt "+d,g.textAlign="center",g.textBaseline="middle",g.strokeStyle="black",g.miterLimit=2,g.lineJoin="circle",g.lineWidth=6,g.strokeText(a,f.width/2,f.height/2),g.lineWidth=2,g.fillStyle=c,g.fillText(a,f.width/2,f.height/2),e&&(g.strokeStyle=e,g.lineWidth=4,g.beginPath(),g.moveTo(0,f.height-10),g.lineTo(f.width-1,f.height-10),g.stroke()),f}};b.exports=d},{}]},{},[1]); \ No newline at end of file diff --git a/display/display-data.js b/display/display-data.js index 47537dc..be1ba36 100644 --- a/display/display-data.js +++ b/display/display-data.js @@ -1,18 +1,18 @@ var data = [ - {lat:42.35843,lng:-71.05977, label: "Boston"}, - {lat:25.77427,lng:-80.19366, label: "Miami"}, - {lat:37.77493,lng:-122.41942, label: "San Francisco"}, - {lat:-23.5475,lng:-46.63611, label: "Sao Paulo"}, - {lat:-12.04318,lng:-77.02824, label: "Lima"}, - {lat:21.30694,lng:-157.85833, label: "Honolulu"}, - {lat:-31.95224,lng:115.8614, label: "Perth"}, - {lat:-33.86785,lng:151.20732, label: "Sydney"}, - {lat: -42, lng: 174, label: "New Zealand"}, - {lat:22.28552,lng:114.15769, label: "Hong Kong"}, - {lat:19.07283,lng:72.88261, label: "Mumbai"}, - {lat:30.06263,lng:31.24967, label:"Cairo"}, - {lat:-33.92584,lng:18.42322, label:"Cape Town"}, - {lat:52.52437,lng:13.41053, label:"Berlin"}, - {lat:55.95206,lng:-3.19648, label:"Edinburgh"}, - {lat:55.75222,lng:37.61556, label:"Moscow"}, + {id: 0, lat:42.35843,lng:-71.05977, label: "Boston"}, + {id: 1, lat:25.77427,lng:-80.19366, label: "Miami"}, + {id: 2, lat:37.77493,lng:-122.41942, label: "San Francisco"}, + {id: 3, lat:-23.5475,lng:-46.63611, label: "Sao Paulo"}, + {id: 4, lat:-12.04318,lng:-77.02824, label: "Lima"}, + {id: 5, lat:21.30694,lng:-157.85833, label: "Honolulu"}, + {id: 6, lat:-31.95224,lng:115.8614, label: "Perth"}, + {id: 7, lat:-33.86785,lng:151.20732, label: "Sydney"}, + {id: 8, lat: -42, lng: 174, label: "New Zealand"}, + {id: 9, lat:22.28552,lng:114.15769, label: "Hong Kong"}, + {id: 10, lat:19.07283,lng:72.88261, label: "Mumbai"}, + {id: 11, lat:30.06263,lng:31.24967, label:"Cairo"}, + {id: 12, lat:-33.92584,lng:18.42322, label:"Cape Town"}, + {id: 13, lat:52.52437,lng:13.41053, label:"Berlin"}, + {id: 14, lat:55.95206,lng:-3.19648, label:"Edinburgh"}, + {id: 15, lat:55.75222,lng:37.61556, label:"Moscow"}, ] diff --git a/display/display.js b/display/display.js index a1ca5c7..494ca28 100644 --- a/display/display.js +++ b/display/display.js @@ -7,6 +7,10 @@ function createGlobe(){ tiles: grid.tiles }); + globe.setClickHandler(function(id){ + alert(id); + }); + // var defaults = { // font: "Inconsolata", // baseColor: "#ffcc00", @@ -17,7 +21,7 @@ function createGlobe(){ // introLinesDuration: 2000, // introLinesColor: "#8FD8D8", // introLinesCount: 60, - // scale: 1.0, + // scale: 1.0, // set to lower if you want the globe to be smaller // dayLength: 28000, // set to 0 if you don't want it to spin // maxPins: 500, // maxMarkers: 4, @@ -29,11 +33,6 @@ function createGlobe(){ $("#globe").append(globe.domElement); - function animate(){ - globe.tick(); - requestAnimationFrame(animate); - } - /* add some satellites in 4 seconds */ setTimeout(function(){ var constellation = []; @@ -56,8 +55,19 @@ function createGlobe(){ globe.addConstellation(constellation, opts); }, 4000); - globe.init(animate); + /* add some of the yellow markers in 2 seconds */ + /* probably should be taken out, but left in in case worth being repurposed */ + setTimeout(function(){ + globe.addMarker(49.25, -123.1, "Vancouver"); + globe.addMarker(35.6895, 129.69171, "Tokyo", true); + }, 2000); + function animate(){ + globe.tick(); + requestAnimationFrame(animate); + } + + globe.init(animate); } /* web font stuff*/ diff --git a/src/Globe.js b/src/Globe.js index 36cb14c..06c9bf0 100644 --- a/src/Globe.js +++ b/src/Globe.js @@ -29,7 +29,7 @@ var addInitialData = function(){ return; } while(this.data.length > 0 && this.firstRunTime + (next = this.data.pop()).when < Date.now()){ - this.addPin(next.lat, next.lng, next.label); + this.addPin(next.lat, next.lng, next.label, next.id); } if(this.firstRunTime + next.when >= Date.now()){ @@ -257,32 +257,68 @@ var createIntroLines = function(){ }; var createMouseBehaviors = function(globe){ - var mouseDown = false, - mousePos = 0, - lastTime = Date.now(), - mouseTimeout; + var mouseDown = false, + mousePos = 0, + lastTime = Date.now(), + movedSinceMouseDown = false, + mouseTimeout, + mouseVector = new THREE.Vector3(0,0,0), + projector = new THREE.Projector(); - globe.domElement.onmousedown = function(e){ mouseDown = true; mousePos = e.clientX; lastTime = Date.now();}; - globe.domElement.onmouseup = function(e){ mouseDown = false; globe.resetRotationSpeed()}; - globe.domElement.onmouseleave = function(e){ mouseDown = false; globe.resetRotationSpeed();}; - var onmousemove = function(e, secondCall){ - var diff = Date.now() - lastTime; - if(mouseDown && diff){ + globe.domElement.onmousedown = function(e){ mouseDown = true; mousePos = e.clientX; lastTime = Date.now(); movedSinceMouseDown=false;}; + globe.domElement.onmouseup = function(e){ mouseDown = false; globe.resetRotationSpeed()}; + globe.domElement.onmouseleave = function(e){ mouseDown = false; globe.resetRotationSpeed();}; - globe.setRotationSpeed(((e.clientX-mousePos)/globe.width) / (diff/1000)); + var onmousemove = function(e, secondCall){ - lastTime = Date.now(); - mousePos = e.clientX; - clearTimeout(mouseTimeout); - if(!secondCall){ - mouseTimeout = setTimeout(function(){onmousemove(e, true)},100); - } + mouseVector.x = 2 * (e.clientX / globe.width) - 1; + mouseVector.y = 1 - 2 *(e.clientY / globe.height); + + var diff = Date.now() - lastTime; + if(mouseDown && diff){ + movedSinceMouseDown = true; + + globe.setRotationSpeed(((e.clientX-mousePos)/globe.width) / (diff/1000)); + + lastTime = Date.now(); + mousePos = e.clientX; + clearTimeout(mouseTimeout); + if(!secondCall){ + mouseTimeout = setTimeout(function(){onmousemove(e, true)},100); + } + } + }; + + var onclick = function (e) { + if(!movedSinceMouseDown){ + var raycaster = projector.pickingRay( mouseVector.clone(), globe.camera ); + var intersects = raycaster.intersectObjects(globe.scene.children); + var minDistance = globe.cameraDistance * 1.1; + var closestObjectId = null; + + for(var i = 0; i 0)){ + var objectDistance = globe.camera.position.distanceTo(intersects[i].object.position); + + if(objectDistance < minDistance){ + minDistance = objectDistance; + closestObjectId = objName; + } + } + } + + if(closestObjectId != null && globe.clickHandler){ + globe.clickHandler(closestObjectId); + } + } } - }; - globe.domElement.onmousemove = onmousemove; -} + globe.domElement.onmousemove = onmousemove; + globe.domElement.onclick = onclick; + +}; /* globe constructor */ @@ -404,7 +440,7 @@ Globe.prototype.destroy = function(callback){ }; -Globe.prototype.addPin = function(lat, lon, text){ +Globe.prototype.addPin = function(lat, lon, text, id){ lat = parseFloat(lat); lon = parseFloat(lon); @@ -412,7 +448,8 @@ Globe.prototype.addPin = function(lat, lon, text){ var opts = { lineColor: this.pinColor, topColor: this.pinColor, - font: this.font + font: this.font, + id: id } var altitude = 1.2; @@ -683,6 +720,11 @@ Globe.prototype.tick = function(){ this.camera.lookAt( this.scene.position ); this.renderer.render( this.scene, this.camera ); + +} + +Globe.prototype.setClickHandler = function(clickHandler){ + this.clickHandler = clickHandler; } module.exports = Globe; diff --git a/src/Pin.js b/src/Pin.js index 57cfbd8..024d5ba 100644 --- a/src/Pin.js +++ b/src/Pin.js @@ -28,7 +28,8 @@ var Pin = function(lat, lon, text, altitude, scene, smokeProvider, _opts){ font: "Inconsolata", showLabel: (text.length > 0), showTop: (text.length > 0), - showSmoke: (text.length > 0) + showSmoke: (text.length > 0), + id: null } var lineMaterial, @@ -90,6 +91,7 @@ var Pin = function(lat, lon, text, altitude, scene, smokeProvider, _opts){ fog: true }); + this.labelSprite = new THREE.Sprite(labelMaterial); this.labelSprite.position = {x: point.x*altitude*1.1, y: point.y*altitude + (point.y < 0 ? -15 : 30), z: point.z*altitude*1.1}; this.labelSprite.scale.set(labelCanvas.width, labelCanvas.height); @@ -141,6 +143,13 @@ var Pin = function(lat, lon, text, altitude, scene, smokeProvider, _opts){ _this.lineGeometry.verticesNeedUpdate = true; }).start(); + /* add in ids for later reference */ + if(this.opts.id !== null && this.opts.id !== undefined){ + this.labelSprite.name = this.opts.id; + this.line.name = this.opts.id; + this.topSprite.name = this.opts.id; + } + /* add to scene */ this.scene.add(this.labelSprite); From b8f3f22e15f113afd70901f59f350e600793089d Mon Sep 17 00:00:00 2001 From: Rob Scanlon Date: Sat, 27 Feb 2016 16:03:33 -0500 Subject: [PATCH 3/5] shrink the collision radius a bit --- build/encom-globe.js | 2 +- build/encom-globe.min.js | 2 +- src/Globe.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/encom-globe.js b/build/encom-globe.js index 97738f6..c112c59 100644 --- a/build/encom-globe.js +++ b/build/encom-globe.js @@ -44147,7 +44147,7 @@ var latLonToXYZ = function(width, height, lat,lon){ var latLon2d = function(lat,lon){ - var rad = 2 + (Math.abs(lat)/90) * 15; + var rad = 2 + (Math.abs(lat)/90) * 5; return {x: lat+90, y:lon + 180, rad: rad}; }; diff --git a/build/encom-globe.min.js b/build/encom-globe.min.js index c3a52b3..37ddaa7 100644 --- a/build/encom-globe.min.js +++ b/build/encom-globe.min.js @@ -14,5 +14,5 @@ m[n]>=0&&a.numSupportedMorphTargets++}if(a.morphNormals){a.numSupportedMorphNorm m.curves=l.curves,n.push(m),n;var o=!e.Shape.Utils.isClockWise(i[0].getPoints());o=a?!o:o;var p,q=[],r=[],s=[],t=0;for(r[t]=void 0,s[t]=[],c=0,d=i.length;d>c;c++)l=i[c],p=l.getPoints(),k=e.Shape.Utils.isClockWise(p),k=a?!k:k,k?(!o&&r[t]&&t++,r[t]={s:new e.Shape,p:p},r[t].s.actions=l.actions,r[t].s.curves=l.curves,o&&t++,s[t]=[]):s[t].push({h:l,p:p[0]});if(r.length>1){for(var u=!1,v=[],w=0,x=r.length;x>w;w++)q[w]=[];for(var w=0,x=r.length;x>w;w++)for(var y=(r[w],s[w]),z=0;z0&&(u||(s=q))}var D,E,F;for(c=0,d=r.length;d>c;c++)for(m=r[c].s,n.push(m),D=s[c],E=0,F=D.length;F>E;E++)m.holes.push(D[E].h);return n},e.Shape=function(){e.Path.apply(this,arguments),this.holes=[]},e.Shape.prototype=Object.create(e.Path.prototype),e.Shape.prototype.extrude=function(a){var b=new e.ExtrudeGeometry(this,a);return b},e.Shape.prototype.makeGeometry=function(a){var b=new e.ShapeGeometry(this,a);return b},e.Shape.prototype.getPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;c>b;b++)d[b]=this.holes[b].getTransformedPoints(a,this.bends);return d},e.Shape.prototype.getSpacedPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;c>b;b++)d[b]=this.holes[b].getTransformedSpacedPoints(a,this.bends);return d},e.Shape.prototype.extractAllPoints=function(a){return{shape:this.getTransformedPoints(a),holes:this.getPointsHoles(a)}},e.Shape.prototype.extractPoints=function(a){return this.useSpacedPoints?this.extractAllSpacedPoints(a):this.extractAllPoints(a)},e.Shape.prototype.extractAllSpacedPoints=function(a){return{shape:this.getTransformedSpacedPoints(a),holes:this.getSpacedPointsHoles(a)}},e.Shape.Utils={triangulateShape:function(a,b){function c(a,b,c){return a.x!=b.x?a.xg){var p;if(n>0){if(0>o||o>n)return[];if(p=k*l-j*m,0>p||p>n)return[]}else{if(o>0||n>o)return[];if(p=k*l-j*m,p>0||n>p)return[]}if(0==p)return!f||0!=o&&o!=n?[a]:[];if(p==n)return!f||0!=o&&o!=n?[b]:[];if(0==o)return[d];if(o==n)return[e];var q=p/n;return[{x:a.x+q*h,y:a.y+q*i}]}if(0!=o||k*l!=j*m)return[];var r=0==h&&0==i,s=0==j&&0==k;if(r&&s)return a.x!=d.x||a.y!=d.y?[]:[a];if(r)return c(d,e,a)?[a]:[];if(s)return c(a,b,d)?[d]:[];var t,u,v,w,x,y,z,A;return 0!=h?(a.x=v?z>w?[]:w==z?f?[]:[x]:A>=w?[x,u]:[x,y]:v>A?[]:v==A?f?[]:[t]:A>=w?[t,u]:[t,y]}function f(a,b,c,d){var e=1e-10,f=b.x-a.x,g=b.y-a.y,h=c.x-a.x,i=c.y-a.y,j=d.x-a.x,k=d.y-a.y,l=f*i-g*h,m=f*k-g*j;if(Math.abs(l)>e){var n=j*i-k*h;return l>0?m>=0&&n>=0:m>=0||n>=0}return m>0}function g(a,b){function c(a,b){var c=s.length-1,d=a-1;0>d&&(d=c);var e=a+1;e>c&&(e=0);var g=f(s[a],s[d],s[e],h[b]);if(!g)return!1;var i=h.length-1,j=b-1;0>j&&(j=i);var k=b+1;return k>i&&(k=0),g=f(h[b],h[j],h[k],s[a]),!!g}function e(a,b){var c,e,f;for(c=0;c0)return!0;return!1}function g(a,c){var e,f,g,h,i;for(e=0;e0)return!0;return!1}for(var h,i,j,k,l,m,n,o,p,q,r,s=a.concat(),t=[],u=[],v=0,w=b.length;w>v;v++)t.push(v);for(var x=2*t.length;t.length>0;){if(x--,0>x){console.log("Infinite Loop! Holes left:"+t.length+", Probably Hole outside Shape!");break}for(j=0;j=0)break;u[n]=!0}if(i>=0)break}}return s}for(var h,i,j,k,l,m,n={},o=a.concat(),p=0,q=b.length;q>p;p++)Array.prototype.push.apply(o,b[p]);for(h=0,i=o.length;i>h;h++)l=o[h].x+":"+o[h].y,void 0!==n[l]&&console.log("Duplicate point",l),n[l]=h;var r=g(a,b),s=e.FontUtils.Triangulate(r,!1);for(h=0,i=s.length;i>h;h++)for(k=s[h],j=0;3>j;j++)l=k[j].x+":"+k[j].y,m=n[l],void 0!==m&&(k[j]=m);return s.concat()},isClockWise:function(a){return e.FontUtils.Triangulate.area(a)<0},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){var c=1-a;return 3*c*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a,b)+this.b3p1(a,c)+this.b3p2(a,d)+this.b3p3(a,e)}},e.LineCurve=function(a,b){this.v1=a,this.v2=b},e.LineCurve.prototype=Object.create(e.Curve.prototype),e.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);return b.multiplyScalar(a).add(this.v1),b},e.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)},e.LineCurve.prototype.getTangent=function(a){var b=this.v2.clone().sub(this.v1);return b.normalize()},e.QuadraticBezierCurve=function(a,b,c){this.v0=a,this.v1=b,this.v2=c},e.QuadraticBezierCurve.prototype=Object.create(e.Curve.prototype),e.QuadraticBezierCurve.prototype.getPoint=function(a){var b,c;return b=e.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x),c=e.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y),new e.Vector2(b,c)},e.QuadraticBezierCurve.prototype.getTangent=function(a){var b,c;b=e.Curve.Utils.tangentQuadraticBezier(a,this.v0.x,this.v1.x,this.v2.x),c=e.Curve.Utils.tangentQuadraticBezier(a,this.v0.y,this.v1.y,this.v2.y);var d=new e.Vector2(b,c);return d.normalize(),d},e.CubicBezierCurve=function(a,b,c,d){this.v0=a,this.v1=b,this.v2=c,this.v3=d},e.CubicBezierCurve.prototype=Object.create(e.Curve.prototype),e.CubicBezierCurve.prototype.getPoint=function(a){var b,c;return b=e.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),c=e.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y),new e.Vector2(b,c)},e.CubicBezierCurve.prototype.getTangent=function(a){var b,c;b=e.Curve.Utils.tangentCubicBezier(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),c=e.Curve.Utils.tangentCubicBezier(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);var d=new e.Vector2(b,c);return d.normalize(),d},e.SplineCurve=function(a){this.points=void 0==a?[]:a},e.SplineCurve.prototype=Object.create(e.Curve.prototype),e.SplineCurve.prototype.getPoint=function(a){var b,c,d,f=new e.Vector2,g=[],h=this.points;return b=(h.length-1)*a,c=Math.floor(b),d=b-c,g[0]=0==c?c:c-1,g[1]=c,g[2]=c>h.length-2?h.length-1:c+1,g[3]=c>h.length-3?h.length-1:c+2,f.x=e.Curve.Utils.interpolate(h[g[0]].x,h[g[1]].x,h[g[2]].x,h[g[3]].x,d),f.y=e.Curve.Utils.interpolate(h[g[0]].y,h[g[1]].y,h[g[2]].y,h[g[3]].y,d),f},e.EllipseCurve=function(a,b,c,d,e,f,g){this.aX=a,this.aY=b,this.xRadius=c,this.yRadius=d,this.aStartAngle=e,this.aEndAngle=f,this.aClockwise=g},e.EllipseCurve.prototype=Object.create(e.Curve.prototype),e.EllipseCurve.prototype.getPoint=function(a){var b,c=this.aEndAngle-this.aStartAngle;0>c&&(c+=2*Math.PI),c>2*Math.PI&&(c-=2*Math.PI),b=this.aClockwise===!0?this.aEndAngle+(1-a)*(2*Math.PI-c):this.aStartAngle+a*c;var d=this.aX+this.xRadius*Math.cos(b),f=this.aY+this.yRadius*Math.sin(b);return new e.Vector2(d,f)},e.ArcCurve=function(a,b,c,d,f,g){e.EllipseCurve.call(this,a,b,c,c,d,f,g)},e.ArcCurve.prototype=Object.create(e.EllipseCurve.prototype),e.LineCurve3=e.Curve.create(function(a,b){this.v1=a,this.v2=b},function(a){var b=new e.Vector3;return b.subVectors(this.v2,this.v1),b.multiplyScalar(a),b.add(this.v1),b}),e.QuadraticBezierCurve3=e.Curve.create(function(a,b,c){this.v0=a,this.v1=b,this.v2=c},function(a){var b,c,d;return b=e.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x),c=e.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y),d=e.Shape.Utils.b2(a,this.v0.z,this.v1.z,this.v2.z),new e.Vector3(b,c,d)}),e.CubicBezierCurve3=e.Curve.create(function(a,b,c,d){this.v0=a,this.v1=b,this.v2=c,this.v3=d},function(a){var b,c,d;return b=e.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),c=e.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y),d=e.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z),new e.Vector3(b,c,d)}),e.SplineCurve3=e.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b,c,d,f=new e.Vector3,g=[],h=this.points;b=(h.length-1)*a,c=Math.floor(b),d=b-c,g[0]=0==c?c:c-1,g[1]=c,g[2]=c>h.length-2?h.length-1:c+1,g[3]=c>h.length-3?h.length-1:c+2;var i=h[g[0]],j=h[g[1]],k=h[g[2]],l=h[g[3]];return f.x=e.Curve.Utils.interpolate(i.x,j.x,k.x,l.x,d),f.y=e.Curve.Utils.interpolate(i.y,j.y,k.y,l.y,d),f.z=e.Curve.Utils.interpolate(i.z,j.z,k.z,l.z,d),f}),e.ClosedSplineCurve3=e.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b,c,d,f=new e.Vector3,g=[],h=this.points;return b=(h.length-0)*a,c=Math.floor(b),d=b-c,c+=c>0?0:(Math.floor(Math.abs(c)/h.length)+1)*h.length,g[0]=(c-1)%h.length,g[1]=c%h.length,g[2]=(c+1)%h.length,g[3]=(c+2)%h.length,f.x=e.Curve.Utils.interpolate(h[g[0]].x,h[g[1]].x,h[g[2]].x,h[g[3]].x,d),f.y=e.Curve.Utils.interpolate(h[g[0]].y,h[g[1]].y,h[g[2]].y,h[g[3]].y,d),f.z=e.Curve.Utils.interpolate(h[g[0]].z,h[g[1]].z,h[g[2]].z,h[g[3]].z,d),f}),e.AnimationHandler=function(){var a=[],b={},c={};c.update=function(b){for(var c=0;ca;a++){var c=this.hierarchy[a];c.matrixAutoUpdate=!0,void 0===c.animationCache&&(c.animationCache={},c.animationCache.prevKey={pos:0,rot:0,scl:0},c.animationCache.nextKey={pos:0,rot:0,scl:0},c.animationCache.originalMatrix=c instanceof e.Bone?c.skinMatrix:c.matrix);var d=c.animationCache.prevKey,f=c.animationCache.nextKey;d.pos=this.data.hierarchy[a].keys[0],d.rot=this.data.hierarchy[a].keys[0],d.scl=this.data.hierarchy[a].keys[0],f.pos=this.getNextKeyWith("pos",a,1),f.rot=this.getNextKeyWith("rot",a,1),f.scl=this.getNextKeyWith("scl",a,1)}},e.Animation.prototype.update=function(){var a=[],b=new e.Vector3,c=function(a,b){var c,e,f,g,h,i,j,k,l,m=[],n=[];return c=(a.length-1)*b,e=Math.floor(c),f=c-e,m[0]=0===e?e:e-1,m[1]=e,m[2]=e>a.length-2?e:e+1,m[3]=e>a.length-3?e:e+2,i=a[m[0]],j=a[m[1]],k=a[m[2]],l=a[m[3]],g=f*f,h=f*g,n[0]=d(i[0],j[0],k[0],l[0],f,g,h),n[1]=d(i[1],j[1],k[1],l[1],f,g,h),n[2]=d(i[2],j[2],k[2],l[2],f,g,h),n},d=function(a,b,c,d,e,f,g){var h=.5*(c-a),i=.5*(d-b);return(2*(b-c)+h+i)*g+(-3*(b-c)-2*h-i)*f+h*e+b};return function(d){if(this.isPlaying!==!1){this.currentTime+=d*this.timeScale;var f,g=["pos","rot","scl"],h=this.data.length;if(this.loop===!0&&this.currentTime>h)this.currentTime%=h,this.reset();else if(this.loop===!1&&this.currentTime>h)return void this.stop();this.currentTime=Math.min(this.currentTime,h);for(var i=0,j=this.hierarchy.length;j>i;i++)for(var k=this.hierarchy[i],l=k.animationCache,m=0;3>m;m++){var n=g[m],o=l.prevKey[n],p=l.nextKey[n];if(p.time<=this.currentTime){for(o=this.data.hierarchy[i].keys[0],p=this.getNextKeyWith(n,i,1);p.timeo.index;)o=p,p=this.getNextKeyWith(n,i,p.index+1);l.prevKey[n]=o,l.nextKey[n]=p}k.matrixAutoUpdate=!0,k.matrixWorldNeedsUpdate=!0;var q=(this.currentTime-o.time)/(p.time-o.time),r=o[n],s=p[n];if(0>q&&(q=0),q>1&&(q=1),"pos"===n){if(f=k.position,this.interpolationType===e.AnimationHandler.LINEAR)f.x=r[0]+(s[0]-r[0])*q,f.y=r[1]+(s[1]-r[1])*q,f.z=r[2]+(s[2]-r[2])*q;else if(this.interpolationType===e.AnimationHandler.CATMULLROM||this.interpolationType===e.AnimationHandler.CATMULLROM_FORWARD){a[0]=this.getPrevKeyWith("pos",i,o.index-1).pos,a[1]=r,a[2]=s,a[3]=this.getNextKeyWith("pos",i,p.index+1).pos,q=.33*q+.33;var t=c(a,q);if(f.x=t[0],f.y=t[1],f.z=t[2],this.interpolationType===e.AnimationHandler.CATMULLROM_FORWARD){var u=c(a,1.01*q);b.set(u[0],u[1],u[2]),b.sub(f),b.y=0,b.normalize();var v=Math.atan2(b.x,b.z);k.rotation.set(0,v,0)}}}else"rot"===n?e.Quaternion.slerp(r,s,k.quaternion,q):"scl"===n&&(f=k.scale,f.x=r[0]+(s[0]-r[0])*q,f.y=r[1]+(s[1]-r[1])*q,f.z=r[2]+(s[2]-r[2])*q)}}}}(),e.Animation.prototype.getNextKeyWith=function(a,b,c){var d=this.data.hierarchy[b].keys;for(this.interpolationType===e.AnimationHandler.CATMULLROM||this.interpolationType===e.AnimationHandler.CATMULLROM_FORWARD?c=c0?c:0:c>=0?c:c+d.length;c>=0;c--)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[d.length-1]},e.KeyFrameAnimation=function(a,b){this.root=a,this.data=e.AnimationHandler.get(b),this.hierarchy=e.AnimationHandler.parse(a),this.currentTime=0,this.timeScale=.001,this.isPlaying=!1,this.isPaused=!0,this.loop=!0;for(var c=0,d=this.hierarchy.length;d>c;c++){var f=this.data.hierarchy[c].keys,g=this.data.hierarchy[c].sids,h=this.hierarchy[c];if(f.length&&g){for(var i=0;ib;b++){c=this.hierarchy[b],d=this.data.hierarchy[b],void 0===d.animationCache&&(d.animationCache={},d.animationCache.prevKey=null,d.animationCache.nextKey=null,d.animationCache.originalMatrix=c instanceof e.Bone?c.skinMatrix:c.matrix);var g=this.data.hierarchy[b].keys;g.length&&(d.animationCache.prevKey=g[0],d.animationCache.nextKey=g[1],this.startTime=Math.min(g[0].time,this.startTime),this.endTime=Math.max(g[g.length-1].time,this.endTime))}this.update(0)}this.isPaused=!1,e.AnimationHandler.addToUpdate(this)},e.KeyFrameAnimation.prototype.pause=function(){this.isPaused?e.AnimationHandler.addToUpdate(this):e.AnimationHandler.removeFromUpdate(this),this.isPaused=!this.isPaused},e.KeyFrameAnimation.prototype.stop=function(){this.isPlaying=!1,this.isPaused=!1,e.AnimationHandler.removeFromUpdate(this);for(var a=0;ab&&(this.currentTime%=b),this.currentTime=Math.min(this.currentTime,b);for(var c=0,d=this.hierarchy.length;d>c;c++){var e=this.hierarchy[c],f=this.data.hierarchy[c],g=f.keys,h=f.animationCache;if(g.length){var i=h.prevKey,j=h.nextKey;if(j.time<=this.currentTime){for(;j.timei.index;)i=j,j=g[i.index+1];h.prevKey=i,h.nextKey=j}j.time>=this.currentTime?i.interpolate(j,this.currentTime):i.interpolate(j,j.time),this.data.hierarchy[c].node.updateMatrix(),e.matrixWorldNeedsUpdate=!0}}}},e.KeyFrameAnimation.prototype.getNextKeyWith=function(a,b,c){var d=this.data.hierarchy[b].keys;for(c%=d.length;c=0?c:c+d.length;c>=0;c--)if(d[c].hasTarget(a))return d[c];return d[d.length-1]},e.MorphAnimation=function(a){this.mesh=a,this.frames=a.morphTargetInfluences.length,this.currentTime=0,this.duration=1e3,this.loop=!0,this.isPlaying=!1},e.MorphAnimation.prototype={play:function(){this.isPlaying=!0},pause:function(){this.isPlaying=!1},update:function(){var a=0,b=0;return function(c){if(this.isPlaying!==!1){this.currentTime+=c,this.loop===!0&&this.currentTime>this.duration&&(this.currentTime%=this.duration),this.currentTime=Math.min(this.currentTime,this.duration);var d=this.duration/this.frames,e=Math.floor(this.currentTime/d);e!=b&&(this.mesh.morphTargetInfluences[a]=0,this.mesh.morphTargetInfluences[b]=1,this.mesh.morphTargetInfluences[e]=0,a=b,b=e),this.mesh.morphTargetInfluences[e]=this.currentTime%d/d,this.mesh.morphTargetInfluences[a]=1-this.mesh.morphTargetInfluences[e]}}}()},e.CubeCamera=function(a,b,c){e.Object3D.call(this),this.className="CubeCamera";var d=90,f=1,g=new e.PerspectiveCamera(d,f,a,b);g.up.set(0,-1,0),g.lookAt(new e.Vector3(1,0,0)),this.add(g);var h=new e.PerspectiveCamera(d,f,a,b);h.up.set(0,-1,0),h.lookAt(new e.Vector3(-1,0,0)),this.add(h);var i=new e.PerspectiveCamera(d,f,a,b);i.up.set(0,0,1),i.lookAt(new e.Vector3(0,1,0)),this.add(i);var j=new e.PerspectiveCamera(d,f,a,b);j.up.set(0,0,-1),j.lookAt(new e.Vector3(0,-1,0)),this.add(j);var k=new e.PerspectiveCamera(d,f,a,b);k.up.set(0,-1,0),k.lookAt(new e.Vector3(0,0,1)),this.add(k);var l=new e.PerspectiveCamera(d,f,a,b);l.up.set(0,-1,0),l.lookAt(new e.Vector3(0,0,-1)),this.add(l),this.renderTarget=new e.WebGLRenderTargetCube(c,c,{format:e.RGBFormat,magFilter:e.LinearFilter,minFilter:e.LinearFilter}),this.updateCubeMap=function(a,b){var c=this.renderTarget,d=c.generateMipmaps;c.generateMipmaps=!1,c.activeCubeFace=0,a.render(b,g,c),c.activeCubeFace=1,a.render(b,h,c),c.activeCubeFace=2,a.render(b,i,c),c.activeCubeFace=3,a.render(b,j,c),c.activeCubeFace=4,a.render(b,k,c),c.generateMipmaps=d,c.activeCubeFace=5,a.render(b,l,c)}},e.CubeCamera.prototype=Object.create(e.Object3D.prototype),e.CombinedCamera=function(a,b,c,d,f,g,h){e.Camera.call(this),this.className="CombinedCamera",this.fov=c,this.left=-a/2,this.right=a/2,this.top=b/2,this.bottom=-b/2,this.cameraO=new e.OrthographicCamera(a/-2,a/2,b/2,b/-2,g,h),this.cameraP=new e.PerspectiveCamera(c,a/b,d,f),this.zoom=1,this.toPerspective()},e.CombinedCamera.prototype=Object.create(e.Camera.prototype),e.CombinedCamera.prototype.toPerspective=function(){this.near=this.cameraP.near,this.far=this.cameraP.far,this.cameraP.fov=this.fov/this.zoom,this.cameraP.updateProjectionMatrix(),this.projectionMatrix=this.cameraP.projectionMatrix,this.inPerspectiveMode=!0,this.inOrthographicMode=!1},e.CombinedCamera.prototype.toOrthographic=function(){var a=this.fov,b=this.cameraP.aspect,c=this.cameraP.near,d=this.cameraP.far,e=(c+d)/2,f=Math.tan(a/2)*e,g=2*f,h=g*b,i=h/2;f/=this.zoom,i/=this.zoom,this.cameraO.left=-i,this.cameraO.right=i,this.cameraO.top=f,this.cameraO.bottom=-f,this.cameraO.updateProjectionMatrix(),this.near=this.cameraO.near,this.far=this.cameraO.far,this.projectionMatrix=this.cameraO.projectionMatrix,this.inPerspectiveMode=!1,this.inOrthographicMode=!0},e.CombinedCamera.prototype.setSize=function(a,b){this.cameraP.aspect=a/b,this.left=-a/2,this.right=a/2,this.top=b/2,this.bottom=-b/2},e.CombinedCamera.prototype.setFov=function(a){this.fov=a,this.inPerspectiveMode?this.toPerspective():this.toOrthographic()},e.CombinedCamera.prototype.updateProjectionMatrix=function(){this.inPerspectiveMode?this.toPerspective():(this.toPerspective(),this.toOrthographic())},e.CombinedCamera.prototype.setLens=function(a,b){void 0===b&&(b=24);var c=2*e.Math.radToDeg(Math.atan(b/(2*a)));return this.setFov(c),c},e.CombinedCamera.prototype.setZoom=function(a){this.zoom=a,this.inPerspectiveMode?this.toPerspective():this.toOrthographic()},e.CombinedCamera.prototype.toFrontView=function(){this.rotation.x=0,this.rotation.y=0,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toBackView=function(){this.rotation.x=0,this.rotation.y=Math.PI,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toLeftView=function(){this.rotation.x=0,this.rotation.y=-Math.PI/2,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toRightView=function(){this.rotation.x=0,this.rotation.y=Math.PI/2,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toTopView=function(){this.rotation.x=-Math.PI/2,this.rotation.y=0,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toBottomView=function(){this.rotation.x=Math.PI/2,this.rotation.y=0,this.rotation.z=0,this.rotationAutoUpdate=!1},e.BoxGeometry=function(a,b,c,d,f,g){function h(a,b,c,d,f,g,h,j){var k,l,m,n=i.widthSegments,o=i.heightSegments,p=f/2,q=g/2,r=i.vertices.length;"x"===a&&"y"===b||"y"===a&&"x"===b?k="z":"x"===a&&"z"===b||"z"===a&&"x"===b?(k="y",o=i.depthSegments):("z"===a&&"y"===b||"y"===a&&"z"===b)&&(k="x",n=i.depthSegments);var s=n+1,t=o+1,u=f/n,v=g/o,w=new e.Vector3;for(w[k]=h>0?1:-1,m=0;t>m;m++)for(l=0;s>l;l++){var x=new e.Vector3;x[a]=(l*u-p)*c,x[b]=(m*v-q)*d,x[k]=h,i.vertices.push(x)}for(m=0;o>m;m++)for(l=0;n>l;l++){var y=l+s*m,z=l+s*(m+1),A=l+1+s*(m+1),B=l+1+s*m,C=new e.Vector2(l/n,1-m/o),D=new e.Vector2(l/n,1-(m+1)/o),E=new e.Vector2((l+1)/n,1-(m+1)/o),F=new e.Vector2((l+1)/n,1-m/o),G=new e.Face3(y+r,z+r,B+r);G.normal.copy(w),G.vertexNormals.push(w.clone(),w.clone(),w.clone()),G.materialIndex=j,i.faces.push(G),i.faceVertexUvs[0].push([C,D,F]),G=new e.Face3(z+r,A+r,B+r),G.normal.copy(w),G.vertexNormals.push(w.clone(),w.clone(),w.clone()),G.materialIndex=j,i.faces.push(G),i.faceVertexUvs[0].push([D.clone(),E,F.clone()])}}e.Geometry.call(this),this.className="BoxGeometry";var i=this;this.width=a,this.height=b,this.depth=c,this.widthSegments=d||1,this.heightSegments=f||1,this.depthSegments=g||1;var j=this.width/2,k=this.height/2,l=this.depth/2;h("z","y",-1,-1,this.depth,this.height,j,0),h("z","y",1,-1,this.depth,this.height,-j,1),h("x","z",1,1,this.width,this.depth,k,2),h("x","z",1,-1,this.width,this.depth,-k,3),h("x","y",1,-1,this.width,this.height,l,4),h("x","y",-1,-1,this.width,this.height,-l,5),this.computeCentroids(),this.mergeVertices()},e.BoxGeometry.prototype=Object.create(e.Geometry.prototype),e.CircleGeometry=function(a,b,c,d){e.Geometry.call(this),this.className="CircleGeometry",this.radius=a=a||50,this.segments=b=void 0!==b?Math.max(3,b):8,this.thetaStart=c=void 0!==c?c:0,this.thetaLength=d=void 0!==d?d:2*Math.PI;var f,g=[],h=new e.Vector3,i=new e.Vector2(.5,.5);for(this.vertices.push(h),g.push(i),f=0;b>=f;f++){var j=new e.Vector3,k=c+f/b*d;j.x=a*Math.cos(k),j.y=a*Math.sin(k),this.vertices.push(j),g.push(new e.Vector2((j.x/a+1)/2,(j.y/a+1)/2))}var l=new e.Vector3(0,0,1);for(f=1;b>=f;f++){var m=f,n=f+1,o=0;this.faces.push(new e.Face3(m,n,o,[l.clone(),l.clone(),l.clone()])),this.faceVertexUvs[0].push([g[f].clone(),g[f+1].clone(),i.clone()])}this.computeCentroids(),this.computeFaceNormals(),this.boundingSphere=new e.Sphere(new e.Vector3,a)},e.CircleGeometry.prototype=Object.create(e.Geometry.prototype),e.CubeGeometry=e.BoxGeometry,e.CylinderGeometry=function(a,b,c,d,f,g){e.Geometry.call(this),this.className="CylinderGeometry",this.radiusTop=a=void 0!==a?a:20,this.radiusBottom=b=void 0!==b?b:20,this.height=c=void 0!==c?c:100,this.radialSegments=d=d||8,this.heightSegments=f=f||1,this.openEnded=g=void 0!==g?g:!1;var h,i,j=c/2,k=[],l=[];for(i=0;f>=i;i++){var m=[],n=[],o=i/f,p=o*(b-a)+a;for(h=0;d>=h;h++){var q=h/d,r=new e.Vector3;r.x=p*Math.sin(q*Math.PI*2),r.y=-o*c+j,r.z=p*Math.cos(q*Math.PI*2),this.vertices.push(r),m.push(this.vertices.length-1),n.push(new e.Vector2(q,1-o))}k.push(m),l.push(n)}var s,t,u=(b-a)/c;for(h=0;d>h;h++)for(0!==a?(s=this.vertices[k[0][h]].clone(),t=this.vertices[k[0][h+1]].clone()):(s=this.vertices[k[1][h]].clone(),t=this.vertices[k[1][h+1]].clone()),s.setY(Math.sqrt(s.x*s.x+s.z*s.z)*u).normalize(),t.setY(Math.sqrt(t.x*t.x+t.z*t.z)*u).normalize(),i=0;f>i;i++){var v=k[i][h],w=k[i+1][h],x=k[i+1][h+1],y=k[i][h+1],z=s.clone(),A=s.clone(),B=t.clone(),C=t.clone(),D=l[i][h].clone(),E=l[i+1][h].clone(),F=l[i+1][h+1].clone(),G=l[i][h+1].clone();this.faces.push(new e.Face3(v,w,y,[z,A,C])),this.faceVertexUvs[0].push([D,E,G]),this.faces.push(new e.Face3(w,x,y,[A.clone(),B,C.clone()])),this.faceVertexUvs[0].push([E.clone(),F,G.clone()])}if(g===!1&&a>0)for(this.vertices.push(new e.Vector3(0,j,0)),h=0;d>h;h++){var v=k[0][h],w=k[0][h+1],x=this.vertices.length-1,z=new e.Vector3(0,1,0),A=new e.Vector3(0,1,0),B=new e.Vector3(0,1,0),D=l[0][h].clone(),E=l[0][h+1].clone(),F=new e.Vector2(E.x,0);this.faces.push(new e.Face3(v,w,x,[z,A,B])),this.faceVertexUvs[0].push([D,E,F])}if(g===!1&&b>0)for(this.vertices.push(new e.Vector3(0,-j,0)),h=0;d>h;h++){var v=k[i][h+1],w=k[i][h],x=this.vertices.length-1,z=new e.Vector3(0,-1,0),A=new e.Vector3(0,-1,0),B=new e.Vector3(0,-1,0),D=l[i][h+1].clone(),E=l[i][h].clone(),F=new e.Vector2(E.x,1);this.faces.push(new e.Face3(v,w,x,[z,A,B])),this.faceVertexUvs[0].push([D,E,F])}this.computeCentroids(),this.computeFaceNormals()},e.CylinderGeometry.prototype=Object.create(e.Geometry.prototype),e.ExtrudeGeometry=function(a,b){return"undefined"==typeof a?void(a=[]):(e.Geometry.call(this),this.className="ExtrudeGeometry",a=a instanceof Array?a:[a],this.shapebb=a[a.length-1].getBoundingBox(),this.addShapeList(a,b),this.computeCentroids(),void this.computeFaceNormals())},e.ExtrudeGeometry.prototype=Object.create(e.Geometry.prototype),e.ExtrudeGeometry.prototype.addShapeList=function(a,b){for(var c=a.length,d=0;c>d;d++){var e=a[d];this.addShape(e,b)}},e.ExtrudeGeometry.prototype.addShape=function(a,b){function c(a,b,c){return b?b.clone().multiplyScalar(c).add(a):e.onerror("die, vec not specified")}function d(a,b,c){var d,f,g=1e-10,h=e.Math.sign,i=1,j=a.x-b.x,k=a.y-b.y,l=c.x-a.x,m=c.y-a.y,n=j*j+k*k,o=j*m-k*l;if(Math.abs(o)>g){var p=Math.sqrt(n),q=Math.sqrt(l*l+m*m),r=b.x-k/p,s=b.y+j/p,t=c.x-m/q,u=c.y+l/q,v=((t-r)*m-(u-s)*l)/(j*m-k*l);d=r+j*v-a.x,f=s+k*v-a.y;var w=d*d+f*f;if(2>=w)return new e.Vector2(d,f);i=Math.sqrt(w/2)}else{var x=!1;j>g?l>g&&(x=!0):-g>j?-g>l&&(x=!0):h(k)==h(m)&&(x=!0),x?(d=-k,f=j,i=Math.sqrt(n)):(d=j,f=k,i=Math.sqrt(n/2))}return new e.Vector2(d/i,f/i)}function f(){if(u){var a=0,b=T*a;for(W=0;U>W;W++)S=L[W],j(S[2]+b,S[1]+b,S[0]+b,!0);for(a=w+2*t,b=T*a,W=0;U>W;W++)S=L[W],j(S[0]+b,S[1]+b,S[2]+b,!1)}else{for(W=0;U>W;W++)S=L[W],j(S[2],S[1],S[0],!0);for(W=0;U>W;W++)S=L[W],j(S[0]+T*w,S[1]+T*w,S[2]+T*w,!1)}}function g(){var a=0;for(h(M,a),a+=M.length,D=0,E=J.length;E>D;D++)C=J[D],h(C,a),a+=C.length}function h(a,b){var c,d;for(W=a.length;--W>=0;){c=W,d=W-1,0>d&&(d=a.length-1);var e=0,f=w+2*t;for(e=0;f>e;e++){var g=T*e,h=T*(e+1),i=b+c+g,j=b+d+g,l=b+d+h,m=b+c+h;k(i,j,l,m,a,e,f,c,d)}}}function i(a,b,c){F.vertices.push(new e.Vector3(a,b,c))}function j(c,d,f,g){c+=G,d+=G,f+=G,F.faces.push(new e.Face3(c,d,f,null,null,z));var h=g?B.generateBottomUV(F,a,b,c,d,f):B.generateTopUV(F,a,b,c,d,f);F.faceVertexUvs[0].push(h)}function k(c,d,f,g,h,i,j,k,l){c+=G,d+=G,f+=G,g+=G,F.faces.push(new e.Face3(c,d,g,null,null,A)),F.faces.push(new e.Face3(d,f,g,null,null,A));var m=B.generateSideWallUV(F,a,h,b,c,d,f,g,i,j,k,l);F.faceVertexUvs[0].push([m[0],m[1],m[3]]),F.faceVertexUvs[0].push([m[1],m[2],m[3]])}var l,m,n,o,p,q=void 0!==b.amount?b.amount:100,r=void 0!==b.bevelThickness?b.bevelThickness:6,s=void 0!==b.bevelSize?b.bevelSize:r-2,t=void 0!==b.bevelSegments?b.bevelSegments:3,u=void 0!==b.bevelEnabled?b.bevelEnabled:!0,v=void 0!==b.curveSegments?b.curveSegments:12,w=void 0!==b.steps?b.steps:1,x=b.extrudePath,y=!1,z=b.material,A=b.extrudeMaterial,B=void 0!==b.UVGenerator?b.UVGenerator:e.ExtrudeGeometry.WorldUVGenerator;this.shapebb;x&&(l=x.getSpacedPoints(w),y=!0,u=!1,m=void 0!==b.frames?b.frames:new e.TubeGeometry.FrenetFrames(x,w,!1),n=new e.Vector3,o=new e.Vector3,p=new e.Vector3),u||(t=0,r=0,s=0);var C,D,E,F=this,G=this.vertices.length,H=a.extractPoints(v),I=H.shape,J=H.holes,K=!e.Shape.Utils.isClockWise(I);if(K){for(I=I.reverse(),D=0,E=J.length;E>D;D++)C=J[D],e.Shape.Utils.isClockWise(C)&&(J[D]=C.reverse());K=!1}var L=e.Shape.Utils.triangulateShape(I,J),M=I;for(D=0,E=J.length;E>D;D++)C=J[D],I=I.concat(C);for(var N,O,P,Q,R,S,T=I.length,U=L.length,V=(M.length,180/Math.PI,[]),W=0,X=M.length,Y=X-1,Z=W+1;X>W;W++,Y++,Z++){Y===X&&(Y=0),Z===X&&(Z=0);M[W],M[Y],M[Z];V[W]=d(M[W],M[Y],M[Z])}var $,_=[],aa=V.concat();for(D=0,E=J.length;E>D;D++){for(C=J[D],$=[],W=0,X=C.length,Y=X-1,Z=W+1;X>W;W++,Y++,Z++)Y===X&&(Y=0),Z===X&&(Z=0),$[W]=d(C[W],C[Y],C[Z]);_.push($),aa=aa.concat($)}for(N=0;t>N;N++){for(P=N/t,Q=r*(1-P),O=s*Math.sin(P*Math.PI/2),W=0,X=M.length;X>W;W++)R=c(M[W],V[W],O),i(R.x,R.y,-Q);for(D=0,E=J.length;E>D;D++)for(C=J[D],$=_[D],W=0,X=C.length;X>W;W++)R=c(C[W],$[W],O),i(R.x,R.y,-Q)}for(O=s,W=0;T>W;W++)R=u?c(I[W],aa[W],O):I[W],y?(o.copy(m.normals[0]).multiplyScalar(R.x),n.copy(m.binormals[0]).multiplyScalar(R.y),p.copy(l[0]).add(o).add(n),i(p.x,p.y,p.z)):i(R.x,R.y,0);var ba;for(ba=1;w>=ba;ba++)for(W=0;T>W;W++)R=u?c(I[W],aa[W],O):I[W],y?(o.copy(m.normals[ba]).multiplyScalar(R.x),n.copy(m.binormals[ba]).multiplyScalar(R.y),p.copy(l[ba]).add(o).add(n),i(p.x,p.y,p.z)):i(R.x,R.y,q/w*ba);for(N=t-1;N>=0;N--){for(P=N/t,Q=r*(1-P),O=s*Math.sin(P*Math.PI/2),W=0,X=M.length;X>W;W++)R=c(M[W],V[W],O),i(R.x,R.y,q+Q);for(D=0,E=J.length;E>D;D++)for(C=J[D],$=_[D],W=0,X=C.length;X>W;W++)R=c(C[W],$[W],O),y?i(R.x,R.y+l[w-1].y,l[w-1].x+Q):i(R.x,R.y,q+Q)}f(),g()},e.ExtrudeGeometry.WorldUVGenerator={generateTopUV:function(a,b,c,d,f,g){var h=a.vertices[d].x,i=a.vertices[d].y,j=a.vertices[f].x,k=a.vertices[f].y,l=a.vertices[g].x,m=a.vertices[g].y; return[new e.Vector2(h,i),new e.Vector2(j,k),new e.Vector2(l,m)]},generateBottomUV:function(a,b,c,d,e,f){return this.generateTopUV(a,b,c,d,e,f)},generateSideWallUV:function(a,b,c,d,f,g,h,i,j,k,l,m){var n=a.vertices[f].x,o=a.vertices[f].y,p=a.vertices[f].z,q=a.vertices[g].x,r=a.vertices[g].y,s=a.vertices[g].z,t=a.vertices[h].x,u=a.vertices[h].y,v=a.vertices[h].z,w=a.vertices[i].x,x=a.vertices[i].y,y=a.vertices[i].z;return Math.abs(o-r)<.01?[new e.Vector2(n,1-p),new e.Vector2(q,1-s),new e.Vector2(t,1-v),new e.Vector2(w,1-y)]:[new e.Vector2(o,1-p),new e.Vector2(r,1-s),new e.Vector2(u,1-v),new e.Vector2(x,1-y)]}},e.ExtrudeGeometry.__v1=new e.Vector2,e.ExtrudeGeometry.__v2=new e.Vector2,e.ExtrudeGeometry.__v3=new e.Vector2,e.ExtrudeGeometry.__v4=new e.Vector2,e.ExtrudeGeometry.__v5=new e.Vector2,e.ExtrudeGeometry.__v6=new e.Vector2,e.ShapeGeometry=function(a,b){e.Geometry.call(this),this.className="ShapeGeometry",a instanceof Array==!1&&(a=[a]),this.shapebb=a[a.length-1].getBoundingBox(),this.addShapeList(a,b),this.computeCentroids(),this.computeFaceNormals()},e.ShapeGeometry.prototype=Object.create(e.Geometry.prototype),e.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;d>c;c++)this.addShape(a[c],b);return this},e.ShapeGeometry.prototype.addShape=function(a,b){void 0===b&&(b={});var c,d,f,g=void 0!==b.curveSegments?b.curveSegments:12,h=b.material,i=void 0===b.UVGenerator?e.ExtrudeGeometry.WorldUVGenerator:b.UVGenerator,j=(this.shapebb,this.vertices.length),k=a.extractPoints(g),l=k.shape,m=k.holes,n=!e.Shape.Utils.isClockWise(l);if(n){for(l=l.reverse(),c=0,d=m.length;d>c;c++)f=m[c],e.Shape.Utils.isClockWise(f)&&(m[c]=f.reverse());n=!1}var o=e.Shape.Utils.triangulateShape(l,m),p=l;for(c=0,d=m.length;d>c;c++)f=m[c],l=l.concat(f);var q,r,s=l.length,t=o.length;p.length;for(c=0;s>c;c++)q=l[c],this.vertices.push(new e.Vector3(q.x,q.y,0));for(c=0;t>c;c++){r=o[c];var u=r[0]+j,v=r[1]+j,w=r[2]+j;this.faces.push(new e.Face3(u,v,w,null,null,h)),this.faceVertexUvs[0].push(i.generateBottomUV(this,a,b,u,v,w))}},e.LatheGeometry=function(a,b,c,d){e.Geometry.call(this),this.className="LatheGeometry",b=b||12,c=c||0,d=d||2*Math.PI;for(var f=1/(a.length-1),g=1/b,h=0,i=b;i>=h;h++)for(var j=c+h*g*d,k=Math.cos(j),l=Math.sin(j),m=0,n=a.length;n>m;m++){var o=a[m],p=new e.Vector3;p.x=k*o.x-l*o.y,p.y=l*o.x+k*o.y,p.z=o.z,this.vertices.push(p)}for(var q=a.length,h=0,i=b;i>h;h++)for(var m=0,n=a.length-1;n>m;m++){var r=m+q*h,s=r,t=r+q,k=r+1+q,u=r+1,v=h*g,w=m*f,x=v+g,y=w+f;this.faces.push(new e.Face3(s,t,u)),this.faceVertexUvs[0].push([new e.Vector2(v,w),new e.Vector2(x,w),new e.Vector2(v,y)]),this.faces.push(new e.Face3(t,k,u)),this.faceVertexUvs[0].push([new e.Vector2(x,w),new e.Vector2(x,y),new e.Vector2(v,y)])}this.mergeVertices(),this.computeCentroids(),this.computeFaceNormals(),this.computeVertexNormals()},e.LatheGeometry.prototype=Object.create(e.Geometry.prototype),e.PlaneGeometry=function(a,b,c,d){e.Geometry.call(this),this.className="PlaneGeometry",this.width=a,this.height=b,this.widthSegments=c||1,this.heightSegments=d||1;var f,g,h=a/2,i=b/2,j=this.widthSegments,k=this.heightSegments,l=j+1,m=k+1,n=this.width/j,o=this.height/k,p=new e.Vector3(0,0,1);for(g=0;m>g;g++)for(f=0;l>f;f++){var q=f*n-h,r=g*o-i;this.vertices.push(new e.Vector3(q,-r,0))}for(g=0;k>g;g++)for(f=0;j>f;f++){var s=f+l*g,t=f+l*(g+1),u=f+1+l*(g+1),v=f+1+l*g,w=new e.Vector2(f/j,1-g/k),x=new e.Vector2(f/j,1-(g+1)/k),y=new e.Vector2((f+1)/j,1-(g+1)/k),z=new e.Vector2((f+1)/j,1-g/k),A=new e.Face3(s,t,v);A.normal.copy(p),A.vertexNormals.push(p.clone(),p.clone(),p.clone()),this.faces.push(A),this.faceVertexUvs[0].push([w,x,z]),A=new e.Face3(t,u,v),A.normal.copy(p),A.vertexNormals.push(p.clone(),p.clone(),p.clone()),this.faces.push(A),this.faceVertexUvs[0].push([x.clone(),y,z.clone()])}this.computeCentroids()},e.PlaneGeometry.prototype=Object.create(e.Geometry.prototype),e.RingGeometry=function(a,b,c,d,f,g){e.Geometry.call(this),this.className="RingGeometry",a=a||0,b=b||50,f=void 0!==f?f:0,g=void 0!==g?g:2*Math.PI,c=void 0!==c?Math.max(3,c):8,d=void 0!==d?Math.max(3,d):8;var h,i,j=[],k=a,l=(b-a)/d;for(h=0;d>=h;h++){for(i=0;c>=i;i++){var m=new e.Vector3,n=f+i/c*g;m.x=k*Math.cos(n),m.y=k*Math.sin(n),this.vertices.push(m),j.push(new e.Vector2((m.x/b+1)/2,(m.y/b+1)/2))}k+=l}var o=new e.Vector3(0,0,1);for(h=0;d>h;h++){var p=h*c;for(i=0;c>=i;i++){var n=i+p,q=n+h,r=n+c+h,s=n+c+1+h;this.faces.push(new e.Face3(q,r,s,[o.clone(),o.clone(),o.clone()])),this.faceVertexUvs[0].push([j[q].clone(),j[r].clone(),j[s].clone()]),q=n+h,r=n+c+1+h,s=n+1+h,this.faces.push(new e.Face3(q,r,s,[o.clone(),o.clone(),o.clone()])),this.faceVertexUvs[0].push([j[q].clone(),j[r].clone(),j[s].clone()])}}this.computeCentroids(),this.computeFaceNormals(),this.boundingSphere=new e.Sphere(new e.Vector3,k)},e.RingGeometry.prototype=Object.create(e.Geometry.prototype),e.SphereGeometry=function(a,b,c,d,f,g,h){e.Geometry.call(this),this.className="SphereGeometry",this.radius=a=a||50,this.widthSegments=b=Math.max(3,Math.floor(b)||8),this.heightSegments=c=Math.max(2,Math.floor(c)||6),this.phiStart=d=void 0!==d?d:0,this.phiLength=f=void 0!==f?f:2*Math.PI,this.thetaStart=g=void 0!==g?g:0,this.thetaLength=h=void 0!==h?h:Math.PI;var i,j,k=[],l=[];for(j=0;c>=j;j++){var m=[],n=[];for(i=0;b>=i;i++){var o=i/b,p=j/c,q=new e.Vector3;q.x=-a*Math.cos(d+o*f)*Math.sin(g+p*h),q.y=a*Math.cos(g+p*h),q.z=a*Math.sin(d+o*f)*Math.sin(g+p*h),this.vertices.push(q),m.push(this.vertices.length-1),n.push(new e.Vector2(o,1-p))}k.push(m),l.push(n)}for(j=0;jp;p++)for(this.grid[p]=[],k=p/(C-1),o=a.getPointAt(k),h=F[p],i=G[p],j=H[p],q=0;q=h&&(g=h,m.set(1,0,0)),g>=i&&(g=i,m.set(0,1,0)),g>=j&&m.set(0,0,1),q.crossVectors(n[0],m).normalize(),o[0].crossVectors(n[0],q),p[0].crossVectors(n[0],o[0])}var f,g,h,i,j,k,l,m=(new e.Vector3,new e.Vector3),n=(new e.Vector3,[]),o=[],p=[],q=new e.Vector3,r=new e.Matrix4,s=b+1,t=1e-4;for(this.tangents=n,this.normals=o,this.binormals=p,k=0;s>k;k++)l=k/(s-1),n[k]=a.getTangentAt(l),n[k].normalize();for(d(),k=1;s>k;k++)o[k]=o[k-1].clone(),p[k]=p[k-1].clone(),q.crossVectors(n[k-1],n[k]),q.length()>t&&(q.normalize(),f=Math.acos(e.Math.clamp(n[k-1].dot(n[k]),-1,1)),o[k].applyMatrix4(r.makeRotationAxis(q,f))),p[k].crossVectors(n[k],o[k]);if(c)for(f=Math.acos(e.Math.clamp(o[0].dot(o[s-1]),-1,1)),f/=s-1,n[0].dot(q.crossVectors(o[0],o[s-1]))>0&&(f=-f),k=1;s>k;k++)o[k].applyMatrix4(r.makeRotationAxis(n[k],f*k)),p[k].crossVectors(n[k],o[k])},e.PolyhedronGeometry=function(a,b,c,d){function f(a){var b=a.normalize().clone();b.index=l.vertices.push(b)-1;var c=i(a)/2/Math.PI+.5,d=j(a)/Math.PI+.5;return b.uv=new e.Vector2(c,1-d),b}function g(a,b,c){var d=new e.Face3(a.index,b.index,c.index,[a.clone(),b.clone(),c.clone()]);d.centroid.add(a).add(b).add(c).divideScalar(3),l.faces.push(d);var f=i(d.centroid);l.faceVertexUvs[0].push([k(a.uv,a,f),k(b.uv,b,f),k(c.uv,c,f)])}function h(a,b){for(var c=Math.pow(2,b),d=(Math.pow(4,b),f(l.vertices[a.a])),e=f(l.vertices[a.b]),h=f(l.vertices[a.c]),i=[],j=0;c>=j;j++){i[j]=[];for(var k=f(d.clone().lerp(h,j/c)),m=f(e.clone().lerp(h,j/c)),n=c-j,o=0;n>=o;o++)0==o&&j==c?i[j][o]=k:i[j][o]=f(k.clone().lerp(m,o/n))}for(var j=0;c>j;j++)for(var o=0;2*(c-j)-1>o;o++){var p=Math.floor(o/2);o%2==0?g(i[j][p+1],i[j+1][p],i[j][p]):g(i[j][p+1],i[j+1][p+1],i[j+1][p])}}function i(a){return Math.atan2(a.z,-a.x)}function j(a){return Math.atan2(-a.y,Math.sqrt(a.x*a.x+a.z*a.z))}function k(a,b,c){return 0>c&&1===a.x&&(a=new e.Vector2(a.x-1,a.y)),0===b.x&&0===b.z&&(a=new e.Vector2(c/2/Math.PI+.5,a.y)),a.clone()}e.Geometry.call(this),this.className="PolyhedronGeometry",c=c||1,d=d||0;for(var l=this,m=0,n=a.length;n>m;m++)f(new e.Vector3(a[m][0],a[m][1],a[m][2]));for(var o=this.vertices,p=[],m=0,n=b.length;n>m;m++){var q=o[b[m][0]],r=o[b[m][1]],s=o[b[m][2]];p[m]=new e.Face3(q.index,r.index,s.index,[q.clone(),r.clone(),s.clone()])}for(var m=0,n=p.length;n>m;m++)h(p[m],d);for(var m=0,n=this.faceVertexUvs[0].length;n>m;m++){var t=this.faceVertexUvs[0][m],u=t[0].x,v=t[1].x,w=t[2].x,x=Math.max(u,Math.max(v,w)),y=Math.min(u,Math.min(v,w));x>.9&&.1>y&&(.2>u&&(t[0].x+=1),.2>v&&(t[1].x+=1),.2>w&&(t[2].x+=1))}for(var m=0,n=this.vertices.length;n>m;m++)this.vertices[m].multiplyScalar(c);this.mergeVertices(),this.computeCentroids(),this.computeFaceNormals(),this.boundingSphere=new e.Sphere(new e.Vector3,c)},e.PolyhedronGeometry.prototype=Object.create(e.Geometry.prototype),e.IcosahedronGeometry=function(a,b){this.radius=a,this.detail=b;var c=(1+Math.sqrt(5))/2,d=[[-1,c,0],[1,c,0],[-1,-c,0],[1,-c,0],[0,-1,c],[0,1,c],[0,-1,-c],[0,1,-c],[c,0,-1],[c,0,1],[-c,0,-1],[-c,0,1]],f=[[0,11,5],[0,5,1],[0,1,7],[0,7,10],[0,10,11],[1,5,9],[5,11,4],[11,10,2],[10,7,6],[7,1,8],[3,9,4],[3,4,2],[3,2,6],[3,6,8],[3,8,9],[4,9,5],[2,4,11],[6,2,10],[8,6,7],[9,8,1]];e.PolyhedronGeometry.call(this,d,f,a,b),this.className="IcosahedronGeometry"},e.IcosahedronGeometry.prototype=Object.create(e.Geometry.prototype),e.OctahedronGeometry=function(a,b){var c=[[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]],d=[[0,2,4],[0,4,3],[0,3,5],[0,5,2],[1,2,5],[1,5,3],[1,3,4],[1,4,2]];e.PolyhedronGeometry.call(this,c,d,a,b),this.className="OctahedronGeometry"},e.OctahedronGeometry.prototype=Object.create(e.Geometry.prototype),e.TetrahedronGeometry=function(a,b){this.className="TetrahedronGeometry";var c=[[1,1,1],[-1,-1,1],[-1,1,-1],[1,-1,-1]],d=[[2,1,0],[0,3,2],[1,3,0],[2,3,1]];e.PolyhedronGeometry.call(this,c,d,a,b)},e.TetrahedronGeometry.prototype=Object.create(e.Geometry.prototype),e.ParametricGeometry=function(a,b,c){e.Geometry.call(this),this.className="ParametricGeometry";var d,f,g,h,i,j=this.vertices,k=this.faces,l=this.faceVertexUvs[0],m=b+1;for(d=0;c>=d;d++)for(i=d/c,f=0;b>=f;f++)h=f/b,g=a(h,i),j.push(g);var n,o,p,q,r,s,t,u;for(d=0;c>d;d++)for(f=0;b>f;f++)n=d*m+f,o=d*m+f+1,p=(d+1)*m+f+1,q=(d+1)*m+f,r=new e.Vector2(f/b,d/c),s=new e.Vector2((f+1)/b,d/c),t=new e.Vector2((f+1)/b,(d+1)/c),u=new e.Vector2(f/b,(d+1)/c),k.push(new e.Face3(n,o,q)),l.push([r,s,u]),k.push(new e.Face3(o,p,q)),l.push([s.clone(),t,u.clone()]);this.computeCentroids(),this.computeFaceNormals(),this.computeVertexNormals()},e.ParametricGeometry.prototype=Object.create(e.Geometry.prototype),e.AxisHelper=function(a){a=a||1;var b=new e.Geometry;b.vertices.push(new e.Vector3,new e.Vector3(a,0,0),new e.Vector3,new e.Vector3(0,a,0),new e.Vector3,new e.Vector3(0,0,a)),b.colors.push(new e.Color(16711680),new e.Color(16755200),new e.Color(65280),new e.Color(11206400),new e.Color(255),new e.Color(43775));var c=new e.LineBasicMaterial({vertexColors:e.VertexColors});e.Line.call(this,b,c,e.LinePieces),this.className="AxisHelper"},e.AxisHelper.prototype=Object.create(e.Line.prototype),e.ArrowHelper=function(a,b,c,d,f,g){e.Object3D.call(this),this.className="ArrowHelper",void 0===d&&(d=16776960),void 0===c&&(c=1),void 0===f&&(f=.2*c),void 0===g&&(g=.2*f),this.position=b;var h=new e.Geometry;h.vertices.push(new e.Vector3(0,0,0)),h.vertices.push(new e.Vector3(0,1,0)),this.line=new e.Line(h,new e.LineBasicMaterial({color:d})),this.line.matrixAutoUpdate=!1,this.add(this.line);var i=new e.CylinderGeometry(0,.5,1,5,1);i.applyMatrix((new e.Matrix4).makeTranslation(0,-.5,0)),this.cone=new e.Mesh(i,new e.MeshBasicMaterial({color:d})),this.cone.matrixAutoUpdate=!1,this.add(this.cone),this.setDirection(a),this.setLength(c,f,g)},e.ArrowHelper.prototype=Object.create(e.Object3D.prototype),e.ArrowHelper.prototype.setDirection=function(){var a,b=new e.Vector3;return function(c){c.y>.99999?this.quaternion.set(0,0,0,1):c.y<-.99999?this.quaternion.set(1,0,0,0):(b.set(c.z,0,-c.x).normalize(),a=Math.acos(c.y),this.quaternion.setFromAxisAngle(b,a))}}(),e.ArrowHelper.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a),void 0===c&&(c=.2*b),this.line.scale.set(1,a,1),this.line.updateMatrix(),this.cone.scale.set(c,b,c),this.cone.position.y=a,this.cone.updateMatrix()},e.ArrowHelper.prototype.setColor=function(a){this.line.material.color.setHex(a),this.cone.material.color.setHex(a)},e.BoxHelper=function(a){var b=[new e.Vector3(1,1,1),new e.Vector3(-1,1,1),new e.Vector3(-1,-1,1),new e.Vector3(1,-1,1),new e.Vector3(1,1,-1),new e.Vector3(-1,1,-1),new e.Vector3(-1,-1,-1),new e.Vector3(1,-1,-1)];this.vertices=b;var c=new e.Geometry;c.vertices.push(b[0],b[1],b[1],b[2],b[2],b[3],b[3],b[0],b[4],b[5],b[5],b[6],b[6],b[7],b[7],b[4],b[0],b[4],b[1],b[5],b[2],b[6],b[3],b[7]),e.Line.call(this,c,new e.LineBasicMaterial({color:16776960}),e.LinePieces),void 0!==a&&this.update(a)},e.BoxHelper.prototype=Object.create(e.Line.prototype),e.BoxHelper.prototype.update=function(a){var b=a.geometry;null===b.boundingBox&&b.computeBoundingBox();var c=b.boundingBox.min,d=b.boundingBox.max,e=this.vertices;e[0].set(d.x,d.y,d.z),e[1].set(c.x,d.y,d.z),e[2].set(c.x,c.y,d.z),e[3].set(d.x,c.y,d.z),e[4].set(d.x,d.y,c.z),e[5].set(c.x,d.y,c.z),e[6].set(c.x,c.y,c.z),e[7].set(d.x,c.y,c.z),this.geometry.computeBoundingSphere(),this.geometry.verticesNeedUpdate=!0,this.matrixAutoUpdate=!1,this.matrixWorld=a.matrixWorld},e.BoundingBoxHelper=function(a,b){var c=void 0!==b?b:8947848;this.object=a,this.box=new e.Box3,e.Mesh.call(this,new e.BoxGeometry(1,1,1),new e.MeshBasicMaterial({color:c,wireframe:!0}))},e.BoundingBoxHelper.prototype=Object.create(e.Mesh.prototype),e.BoundingBoxHelper.prototype.update=function(){this.box.setFromObject(this.object),this.box.size(this.scale),this.box.center(this.position)},e.CameraHelper=function(a){function b(a,b,d){c(a,d),c(b,d)}function c(a,b){d.vertices.push(new e.Vector3),d.colors.push(new e.Color(b)),void 0===g[a]&&(g[a]=[]),g[a].push(d.vertices.length-1)}var d=new e.Geometry,f=new e.LineBasicMaterial({color:16777215,vertexColors:e.FaceColors}),g={},h=16755200,i=16711680,j=43775,k=16777215,l=3355443;b("n1","n2",h),b("n2","n4",h),b("n4","n3",h),b("n3","n1",h),b("f1","f2",h),b("f2","f4",h),b("f4","f3",h),b("f3","f1",h),b("n1","f1",h),b("n2","f2",h),b("n3","f3",h),b("n4","f4",h),b("p","n1",i),b("p","n2",i),b("p","n3",i),b("p","n4",i),b("u1","u2",j),b("u2","u3",j),b("u3","u1",j),b("c","t",k),b("p","c",l),b("cn1","cn2",l),b("cn3","cn4",l),b("cf1","cf2",l),b("cf3","cf4",l),e.Line.call(this,d,f,e.LinePieces),this.camera=a,this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1,this.pointMap=g,this.update()},e.CameraHelper.prototype=Object.create(e.Line.prototype),e.CameraHelper.prototype.update=function(){var a=new e.Vector3,b=new e.Camera,c=new e.Projector;return function(){function d(d,f,g,h){a.set(f,g,h),c.unprojectVector(a,b);var i=e.pointMap[d];if(void 0!==i)for(var j=0,k=i.length;k>j;j++)e.geometry.vertices[i[j]].copy(a)}var e=this,f=1,g=1;b.projectionMatrix.copy(this.camera.projectionMatrix),d("c",0,0,-1),d("t",0,0,1),d("n1",-f,-g,-1),d("n2",f,-g,-1),d("n3",-f,g,-1),d("n4",f,g,-1),d("f1",-f,-g,1),d("f2",f,-g,1),d("f3",-f,g,1),d("f4",f,g,1),d("u1",.7*f,1.1*g,-1),d("u2",.7*-f,1.1*g,-1),d("u3",0,2*g,-1),d("cf1",-f,0,1),d("cf2",f,0,1),d("cf3",0,-g,1),d("cf4",0,g,1),d("cn1",-f,0,-1),d("cn2",f,0,-1),d("cn3",0,-g,-1),d("cn4",0,g,-1),this.geometry.verticesNeedUpdate=!0}}(),e.DirectionalLightHelper=function(a,b){e.Object3D.call(this),this.light=a,this.light.updateMatrixWorld(),this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1,b=b||1;var c=new e.PlaneGeometry(b,b),d=new e.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity),this.lightPlane=new e.Mesh(c,d),this.add(this.lightPlane),c=new e.Geometry,c.vertices.push(new e.Vector3),c.vertices.push(new e.Vector3),d=new e.LineBasicMaterial({fog:!1}),d.color.copy(this.light.color).multiplyScalar(this.light.intensity),this.targetLine=new e.Line(c,d),this.add(this.targetLine),this.update()},e.DirectionalLightHelper.prototype=Object.create(e.Object3D.prototype),e.DirectionalLightHelper.prototype.dispose=function(){this.lightPlane.geometry.dispose(),this.lightPlane.material.dispose(),this.targetLine.geometry.dispose(),this.targetLine.material.dispose()},e.DirectionalLightHelper.prototype.update=function(){var a=new e.Vector3,b=new e.Vector3,c=new e.Vector3;return function(){a.setFromMatrixPosition(this.light.matrixWorld),b.setFromMatrixPosition(this.light.target.matrixWorld),c.subVectors(b,a),this.lightPlane.lookAt(c),this.lightPlane.material.color.copy(this.light.color).multiplyScalar(this.light.intensity),this.targetLine.geometry.vertices[1].copy(c),this.targetLine.geometry.verticesNeedUpdate=!0,this.targetLine.material.color.copy(this.lightPlane.material.color)}}(),e.EdgesHelper=function(a,b){var c=void 0!==b?b:16777215,d=[0,0],f={},g=function(a,b){return a-b},h=["a","b","c"],i=new e.BufferGeometry,j=a.geometry.clone();j.mergeVertices(),j.computeFaceNormals();for(var k=j.vertices,l=j.faces,m=0,n=0,o=l.length;o>n;n++)for(var p=l[n],q=0;3>q;q++){d[0]=p[h[q]],d[1]=p[h[(q+1)%3]],d.sort(g);var r=d.toString();void 0===f[r]?(f[r]={vert1:d[0],vert2:d[1],face1:n,face2:void 0},m++):f[r].face2=n}i.addAttribute("position",Float32Array,2*m,3);var s=i.attributes.position.array,t=0;for(var r in f){var u=f[r];if(void 0===u.face2||l[u.face1].normal.dot(l[u.face2].normal)<.9999){var v=k[u.vert1];s[t++]=v.x,s[t++]=v.y,s[t++]=v.z,v=k[u.vert2],s[t++]=v.x,s[t++]=v.y,s[t++]=v.z}}e.Line.call(this,i,new e.LineBasicMaterial({color:c}),e.LinePieces),this.matrixAutoUpdate=!1,this.matrixWorld=a.matrixWorld},e.EdgesHelper.prototype=Object.create(e.Line.prototype),e.FaceNormalsHelper=function(a,b,c,d){this.object=a,this.size=void 0!==b?b:1;for(var f=void 0!==c?c:16776960,g=void 0!==d?d:1,h=new e.Geometry,i=this.object.geometry.faces,j=0,k=i.length;k>j;j++)h.vertices.push(new e.Vector3),h.vertices.push(new e.Vector3);e.Line.call(this,h,new e.LineBasicMaterial({color:f,linewidth:g}),e.LinePieces),this.matrixAutoUpdate=!1,this.normalMatrix=new e.Matrix3,this.update()},e.FaceNormalsHelper.prototype=Object.create(e.Line.prototype),e.FaceNormalsHelper.prototype.update=function(a){var b=new e.Vector3;return function(a){this.object.updateMatrixWorld(!0),this.normalMatrix.getNormalMatrix(this.object.matrixWorld);for(var c=this.geometry.vertices,d=this.object.geometry.faces,e=this.object.matrixWorld,f=0,g=d.length;g>f;f++){var h=d[f];b.copy(h.normal).applyMatrix3(this.normalMatrix).normalize().multiplyScalar(this.size);var i=2*f;c[i].copy(h.centroid).applyMatrix4(e),c[i+1].addVectors(c[i],b)}return this.geometry.verticesNeedUpdate=!0,this}}(),e.GridHelper=function(a,b){var c=new e.Geometry,d=new e.LineBasicMaterial({vertexColors:e.VertexColors});this.color1=new e.Color(4473924),this.color2=new e.Color(8947848);for(var f=-a;a>=f;f+=b){c.vertices.push(new e.Vector3(-a,0,f),new e.Vector3(a,0,f),new e.Vector3(f,0,-a),new e.Vector3(f,0,a));var g=0===f?this.color1:this.color2;c.colors.push(g,g,g,g)}e.Line.call(this,c,d,e.LinePieces)},e.GridHelper.prototype=Object.create(e.Line.prototype),e.GridHelper.prototype.setColors=function(a,b){this.color1.set(a),this.color2.set(b),this.geometry.colorsNeedUpdate=!0},e.HemisphereLightHelper=function(a,b,c,d){e.Object3D.call(this),this.light=a,this.light.updateMatrixWorld(),this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1,this.colors=[new e.Color,new e.Color];var f=new e.SphereGeometry(b,4,2);f.applyMatrix((new e.Matrix4).makeRotationX(-Math.PI/2));for(var g=0,h=8;h>g;g++)f.faces[g].color=this.colors[4>g?0:1];var i=new e.MeshBasicMaterial({vertexColors:e.FaceColors,wireframe:!0});this.lightSphere=new e.Mesh(f,i),this.add(this.lightSphere),this.update()},e.HemisphereLightHelper.prototype=Object.create(e.Object3D.prototype),e.HemisphereLightHelper.prototype.dispose=function(){this.lightSphere.geometry.dispose(),this.lightSphere.material.dispose()},e.HemisphereLightHelper.prototype.update=function(){var a=new e.Vector3;return function(){this.colors[0].copy(this.light.color).multiplyScalar(this.light.intensity),this.colors[1].copy(this.light.groundColor).multiplyScalar(this.light.intensity),this.lightSphere.lookAt(a.setFromMatrixPosition(this.light.matrixWorld).negate()),this.lightSphere.geometry.colorsNeedUpdate=!0}}(),e.PointLightHelper=function(a,b){this.light=a,this.light.updateMatrixWorld();var c=new e.SphereGeometry(b,4,2),d=new e.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity),e.Mesh.call(this,c,d),this.matrixWorld=this.light.matrixWorld,this.matrixAutoUpdate=!1},e.PointLightHelper.prototype=Object.create(e.Mesh.prototype),e.PointLightHelper.prototype.dispose=function(){this.geometry.dispose(),this.material.dispose()},e.PointLightHelper.prototype.update=function(){this.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)},e.SpotLightHelper=function(a){e.Object3D.call(this),this.light=a,this.light.updateMatrixWorld(),this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1;var b=new e.CylinderGeometry(0,1,1,8,1,!0);b.applyMatrix((new e.Matrix4).makeTranslation(0,-.5,0)),b.applyMatrix((new e.Matrix4).makeRotationX(-Math.PI/2));var c=new e.MeshBasicMaterial({wireframe:!0,fog:!1});this.cone=new e.Mesh(b,c),this.add(this.cone),this.update()},e.SpotLightHelper.prototype=Object.create(e.Object3D.prototype),e.SpotLightHelper.prototype.dispose=function(){this.cone.geometry.dispose(),this.cone.material.dispose()},e.SpotLightHelper.prototype.update=function(){var a=new e.Vector3,b=new e.Vector3;return function(){var c=this.light.distance?this.light.distance:1e4,d=c*Math.tan(this.light.angle);this.cone.scale.set(d,d,c),a.setFromMatrixPosition(this.light.matrixWorld),b.setFromMatrixPosition(this.light.target.matrixWorld),this.cone.lookAt(b.sub(a)),this.cone.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)}}(),e.VertexNormalsHelper=function(a,b,c,d){this.object=a,this.size=void 0!==b?b:1;for(var f=void 0!==c?c:16711680,g=void 0!==d?d:1,h=new e.Geometry,i=(a.geometry.vertices,a.geometry.faces),j=0,k=i.length;k>j;j++)for(var l=i[j],m=0,n=l.vertexNormals.length;n>m;m++)h.vertices.push(new e.Vector3),h.vertices.push(new e.Vector3);e.Line.call(this,h,new e.LineBasicMaterial({color:f,linewidth:g}),e.LinePieces),this.matrixAutoUpdate=!1,this.normalMatrix=new e.Matrix3,this.update()},e.VertexNormalsHelper.prototype=Object.create(e.Line.prototype),e.VertexNormalsHelper.prototype.update=function(a){var b=new e.Vector3;return function(a){var c=["a","b","c","d"];this.object.updateMatrixWorld(!0),this.normalMatrix.getNormalMatrix(this.object.matrixWorld);for(var d=this.geometry.vertices,e=this.object.geometry.vertices,f=this.object.geometry.faces,g=this.object.matrixWorld,h=0,i=0,j=f.length;j>i;i++)for(var k=f[i],l=0,m=k.vertexNormals.length;m>l;l++){var n=k[c[l]],o=e[n],p=k.vertexNormals[l];d[h].copy(o).applyMatrix4(g),b.copy(p).applyMatrix3(this.normalMatrix).normalize().multiplyScalar(this.size),b.add(d[h]),h+=1,d[h].copy(b),h+=1}return this.geometry.verticesNeedUpdate=!0,this}}(),e.VertexTangentsHelper=function(a,b,c,d){this.object=a,this.size=void 0!==b?b:1;for(var f=void 0!==c?c:255,g=void 0!==d?d:1,h=new e.Geometry,i=(a.geometry.vertices,a.geometry.faces),j=0,k=i.length;k>j;j++)for(var l=i[j],m=0,n=l.vertexTangents.length;n>m;m++)h.vertices.push(new e.Vector3),h.vertices.push(new e.Vector3);e.Line.call(this,h,new e.LineBasicMaterial({color:f,linewidth:g}),e.LinePieces),this.matrixAutoUpdate=!1,this.update()},e.VertexTangentsHelper.prototype=Object.create(e.Line.prototype),e.VertexTangentsHelper.prototype.update=function(a){var b=new e.Vector3;return function(a){var c=["a","b","c","d"];this.object.updateMatrixWorld(!0);for(var d=this.geometry.vertices,e=this.object.geometry.vertices,f=this.object.geometry.faces,g=this.object.matrixWorld,h=0,i=0,j=f.length;j>i;i++)for(var k=f[i],l=0,m=k.vertexTangents.length;m>l;l++){var n=k[c[l]],o=e[n],p=k.vertexTangents[l];d[h].copy(o).applyMatrix4(g),b.copy(p).transformDirection(g).multiplyScalar(this.size),b.add(d[h]),h+=1,d[h].copy(b),h+=1}return this.geometry.verticesNeedUpdate=!0,this}}(),e.WireframeHelper=function(a,b){var c=void 0!==b?b:16777215,d=[0,0],f={},g=function(a,b){return a-b},h=["a","b","c"],i=new e.BufferGeometry;if(a.geometry instanceof e.Geometry){for(var j=a.geometry.vertices,k=a.geometry.faces,l=0,m=new Uint32Array(6*k.length),n=0,o=k.length;o>n;n++)for(var p=k[n],q=0;3>q;q++){d[0]=p[h[q]],d[1]=p[h[(q+1)%3]],d.sort(g);var r=d.toString();void 0===f[r]&&(m[2*l]=d[0],m[2*l+1]=d[1],f[r]=!0,l++)}i.addAttribute("position",Float32Array,2*l,3);for(var s=i.attributes.position.array,n=0,o=l;o>n;n++)for(var q=0;2>q;q++){var t=j[m[2*n+q]],u=6*n+3*q;s[u+0]=t.x,s[u+1]=t.y,s[u+2]=t.z}}else if(a.geometry instanceof e.BufferGeometry&&void 0!==a.geometry.attributes.index){for(var j=a.geometry.attributes.position.array,v=a.geometry.attributes.index.array,w=a.geometry.offsets,l=0,m=new Uint32Array(2*v.length),x=0,y=w.length;y>x;++x)for(var z=w[x].start,A=w[x].count,u=w[x].index,n=z,B=z+A;B>n;n+=3)for(var q=0;3>q;q++){d[0]=u+v[n+q],d[1]=u+v[n+(q+1)%3],d.sort(g);var r=d.toString();void 0===f[r]&&(m[2*l]=d[0],m[2*l+1]=d[1],f[r]=!0,l++)}i.addAttribute("position",Float32Array,2*l,3);for(var s=i.attributes.position.array,n=0,o=l;o>n;n++)for(var q=0;2>q;q++){var u=6*n+3*q,C=3*m[2*n+q];s[u+0]=j[C],s[u+1]=j[C+1],s[u+2]=j[C+2]}}else if(a.geometry instanceof e.BufferGeometry){var j=a.geometry.attributes.position.array,l=j.length/3,D=l/3;i.addAttribute("position",Float32Array,2*l,3);for(var s=i.attributes.position.array,n=0,o=D;o>n;n++)for(var q=0;3>q;q++){var u=18*n+6*q,E=9*n+3*q;s[u+0]=j[E],s[u+1]=j[E+1],s[u+2]=j[E+2];var C=9*n+3*((q+1)%3);s[u+3]=j[C],s[u+4]=j[C+1],s[u+5]=j[C+2]}}e.Line.call(this,i,new e.LineBasicMaterial({color:c}),e.LinePieces),this.matrixAutoUpdate=!1,this.matrixWorld=a.matrixWorld},e.WireframeHelper.prototype=Object.create(e.Line.prototype),e.ImmediateRenderObject=function(){e.Object3D.call(this),this.render=function(a){}},e.ImmediateRenderObject.prototype=Object.create(e.Object3D.prototype),e.LensFlare=function(a,b,c,d,f){ e.Object3D.call(this),this.lensFlares=[],this.positionScreen=new e.Vector3,this.customUpdateCallback=void 0,void 0!==a&&this.add(a,b,c,d,f)},e.LensFlare.prototype=Object.create(e.Object3D.prototype),e.LensFlare.prototype.add=function(a,b,c,d,f,g){void 0===b&&(b=-1),void 0===c&&(c=0),void 0===g&&(g=1),void 0===f&&(f=new e.Color(16777215)),void 0===d&&(d=e.NormalBlending),c=Math.min(c,Math.max(0,c)),this.lensFlares.push({texture:a,size:b,distance:c,x:0,y:0,z:0,scale:1,rotation:1,opacity:g,color:f,blending:d})},e.LensFlare.prototype.updateLensFlares=function(){var a,b,c=this.lensFlares.length,d=2*-this.positionScreen.x,e=2*-this.positionScreen.y;for(a=0;c>a;a++)b=this.lensFlares[a],b.x=this.positionScreen.x+d*b.distance,b.y=this.positionScreen.y+e*b.distance,b.wantedRotation=b.x*Math.PI*.25,b.rotation+=.25*(b.wantedRotation-b.rotation)},e.MorphBlendMesh=function(a,b){e.Mesh.call(this,a,b),this.animationsMap={},this.animationsList=[];var c=this.geometry.morphTargets.length,d="__default",f=0,g=c-1,h=c/1;this.createAnimation(d,f,g,h),this.setAnimationWeight(d,1)},e.MorphBlendMesh.prototype=Object.create(e.Mesh.prototype),e.MorphBlendMesh.prototype.createAnimation=function(a,b,c,d){var e={startFrame:b,endFrame:c,length:c-b+1,fps:d,duration:(c-b)/d,lastFrame:0,currentFrame:0,active:!1,time:0,direction:1,weight:1,directionBackwards:!1,mirroredLoop:!1};this.animationsMap[a]=e,this.animationsList.push(e)},e.MorphBlendMesh.prototype.autoCreateAnimations=function(a){for(var b,c=/([a-z]+)(\d+)/,d={},e=this.geometry,f=0,g=e.morphTargets.length;g>f;f++){var h=e.morphTargets[f],i=h.name.match(c);if(i&&i.length>1){var j=i[1];i[2];d[j]||(d[j]={start:1/0,end:-(1/0)});var k=d[j];fk.end&&(k.end=f),b||(b=j)}}for(var j in d){var k=d[j];this.createAnimation(j,k.start,k.end,a)}this.firstAnimation=b},e.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){var b=this.animationsMap[a];b&&(b.direction=1,b.directionBackwards=!1)},e.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){var b=this.animationsMap[a];b&&(b.direction=-1,b.directionBackwards=!0)},e.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)},e.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)},e.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)},e.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)},e.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0,c=this.animationsMap[a];return c&&(b=c.time),b},e.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1,c=this.animationsMap[a];return c&&(b=c.duration),b},e.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):e.onwarning("animation["+a+"] undefined")},e.MorphBlendMesh.prototype.stopAnimation=function(a){var b=this.animationsMap[a];b&&(b.active=!1)},e.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;c>b;b++){var d=this.animationsList[b];if(d.active){var f=d.duration/d.length;d.time+=d.direction*a,d.mirroredLoop?(d.time>d.duration||d.time<0)&&(d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),d.time<0&&(d.time=0,d.directionBackwards=!1)):(d.time=d.time%d.duration,d.time<0&&(d.time+=d.duration));var g=d.startFrame+e.Math.clamp(Math.floor(d.time/f),0,d.length-1),h=d.weight;g!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*h,this.morphTargetInfluences[g]=0,d.lastFrame=d.currentFrame,d.currentFrame=g);var i=d.time%f/f;d.directionBackwards&&(i=1-i),this.morphTargetInfluences[d.currentFrame]=i*h,this.morphTargetInfluences[d.lastFrame]=(1-i)*h}}},e.LensFlarePlugin=function(){function a(a,c){var d=b.createProgram(),e=b.createShader(b.FRAGMENT_SHADER),f=b.createShader(b.VERTEX_SHADER),g="precision "+c+" float;\n";return b.shaderSource(e,g+a.fragmentShader),b.shaderSource(f,g+a.vertexShader),b.compileShader(e),b.compileShader(f),b.attachShader(d,e),b.attachShader(d,f),b.linkProgram(d),d}var b,c,d,f={};this.init=function(g){b=g.context,c=g,d=g.getPrecision(),f.vertices=new Float32Array(16),f.faces=new Uint16Array(6);var h=0;f.vertices[h++]=-1,f.vertices[h++]=-1,f.vertices[h++]=0,f.vertices[h++]=0,f.vertices[h++]=1,f.vertices[h++]=-1,f.vertices[h++]=1,f.vertices[h++]=0,f.vertices[h++]=1,f.vertices[h++]=1,f.vertices[h++]=1,f.vertices[h++]=1,f.vertices[h++]=-1,f.vertices[h++]=1,f.vertices[h++]=0,f.vertices[h++]=1,h=0,f.faces[h++]=0,f.faces[h++]=1,f.faces[h++]=2,f.faces[h++]=0,f.faces[h++]=2,f.faces[h++]=3,f.vertexBuffer=b.createBuffer(),f.elementBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,f.vertexBuffer),b.bufferData(b.ARRAY_BUFFER,f.vertices,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,f.elementBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,f.faces,b.STATIC_DRAW),f.tempTexture=b.createTexture(),f.occlusionTexture=b.createTexture(),b.bindTexture(b.TEXTURE_2D,f.tempTexture),b.texImage2D(b.TEXTURE_2D,0,b.RGB,16,16,0,b.RGB,b.UNSIGNED_BYTE,null),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST),b.bindTexture(b.TEXTURE_2D,f.occlusionTexture),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,16,16,0,b.RGBA,b.UNSIGNED_BYTE,null),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST),b.getParameter(b.MAX_VERTEX_TEXTURE_IMAGE_UNITS)<=0?(f.hasVertexTexture=!1,f.program=a(e.ShaderFlares.lensFlare,d)):(f.hasVertexTexture=!0,f.program=a(e.ShaderFlares.lensFlareVertexTexture,d)),f.attributes={},f.uniforms={},f.attributes.vertex=b.getAttribLocation(f.program,"position"),f.attributes.uv=b.getAttribLocation(f.program,"uv"),f.uniforms.renderType=b.getUniformLocation(f.program,"renderType"),f.uniforms.map=b.getUniformLocation(f.program,"map"),f.uniforms.occlusionMap=b.getUniformLocation(f.program,"occlusionMap"),f.uniforms.opacity=b.getUniformLocation(f.program,"opacity"),f.uniforms.color=b.getUniformLocation(f.program,"color"),f.uniforms.scale=b.getUniformLocation(f.program,"scale"),f.uniforms.rotation=b.getUniformLocation(f.program,"rotation"),f.uniforms.screenPosition=b.getUniformLocation(f.program,"screenPosition")},this.render=function(a,d,g,h){var i=a.__webglFlares,j=i.length;if(j){var k=new e.Vector3,l=h/g,m=.5*g,n=.5*h,o=16/h,p=new e.Vector2(o*l,o),q=new e.Vector3(1,1,0),r=new e.Vector2(1,1),s=f.uniforms,t=f.attributes;b.useProgram(f.program),b.enableVertexAttribArray(f.attributes.vertex),b.enableVertexAttribArray(f.attributes.uv),b.uniform1i(s.occlusionMap,0),b.uniform1i(s.map,1),b.bindBuffer(b.ARRAY_BUFFER,f.vertexBuffer),b.vertexAttribPointer(t.vertex,2,b.FLOAT,!1,16,0),b.vertexAttribPointer(t.uv,2,b.FLOAT,!1,16,8),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,f.elementBuffer),b.disable(b.CULL_FACE),b.depthMask(!1);var u,v,w,x,y;for(u=0;j>u;u++)if(o=16/h,p.set(o*l,o),x=i[u],k.set(x.matrixWorld.elements[12],x.matrixWorld.elements[13],x.matrixWorld.elements[14]),k.applyMatrix4(d.matrixWorldInverse),k.applyProjection(d.projectionMatrix),q.copy(k),r.x=q.x*m+m,r.y=q.y*n+n,f.hasVertexTexture||r.x>0&&r.x0&&r.yv;v++)y=x.lensFlares[v],y.opacity>.001&&y.scale>.001&&(q.x=y.x,q.y=y.y,q.z=y.z,o=y.size*y.scale/h,p.x=o*l,p.y=o,b.uniform3f(s.screenPosition,q.x,q.y,q.z),b.uniform2f(s.scale,p.x,p.y),b.uniform1f(s.rotation,y.rotation),b.uniform1f(s.opacity,y.opacity),b.uniform3f(s.color,y.color.r,y.color.g,y.color.b),c.setBlending(y.blending,y.blendEquation,y.blendSrc,y.blendDst),c.setTexture(y.texture,1),b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0));b.enable(b.CULL_FACE),b.enable(b.DEPTH_TEST),b.depthMask(!0)}}},e.ShadowMapPlugin=function(){function a(a,b){var c=new e.DirectionalLight;c.isVirtual=!0,c.onlyShadow=!0,c.castShadow=!0,c.shadowCameraNear=a.shadowCameraNear,c.shadowCameraFar=a.shadowCameraFar,c.shadowCameraLeft=a.shadowCameraLeft,c.shadowCameraRight=a.shadowCameraRight,c.shadowCameraBottom=a.shadowCameraBottom,c.shadowCameraTop=a.shadowCameraTop,c.shadowCameraVisible=a.shadowCameraVisible,c.shadowDarkness=a.shadowDarkness,c.shadowBias=a.shadowCascadeBias[b],c.shadowMapWidth=a.shadowCascadeWidth[b],c.shadowMapHeight=a.shadowCascadeHeight[b],c.pointsWorld=[],c.pointsFrustum=[];for(var d=c.pointsWorld,f=c.pointsFrustum,g=0;8>g;g++)d[g]=new e.Vector3,f[g]=new e.Vector3;var h=a.shadowCascadeNearZ[b],i=a.shadowCascadeFarZ[b];return f[0].set(-1,-1,h),f[1].set(1,-1,h),f[2].set(-1,1,h),f[3].set(1,1,h),f[4].set(-1,-1,i),f[5].set(1,-1,i),f[6].set(-1,1,i),f[7].set(1,1,i),c}function b(a,b){var c=a.shadowCascadeArray[b];c.position.copy(a.position),c.target.position.copy(a.target.position),c.lookAt(c.target),c.shadowCameraVisible=a.shadowCameraVisible,c.shadowDarkness=a.shadowDarkness,c.shadowBias=a.shadowCascadeBias[b];var d=a.shadowCascadeNearZ[b],e=a.shadowCascadeFarZ[b],f=c.pointsFrustum;f[0].z=d,f[1].z=d,f[2].z=d,f[3].z=d,f[4].z=e,f[5].z=e,f[6].z=e,f[7].z=e}function c(a,b){var c=b.shadowCamera,d=b.pointsFrustum,f=b.pointsWorld;n.set(1/0,1/0,1/0),o.set(-(1/0),-(1/0),-(1/0));for(var g=0;8>g;g++){var h=f[g];h.copy(d[g]),e.ShadowMapPlugin.__projector.unprojectVector(h,a),h.applyMatrix4(c.matrixWorldInverse),h.xo.x&&(o.x=h.x),h.yo.y&&(o.y=h.y),h.zo.z&&(o.z=h.z)}c.left=n.x,c.right=o.x,c.top=o.y,c.bottom=n.y,c.updateProjectionMatrix()}function d(a){return a.material instanceof e.MeshFaceMaterial?a.material.materials[0]:a.material}var f,g,h,i,j,k,l=new e.Frustum,m=new e.Matrix4,n=new e.Vector3,o=new e.Vector3,p=new e.Vector3;this.init=function(a){f=a.context,g=a;var b=e.ShaderLib.depthRGBA,c=e.UniformsUtils.clone(b.uniforms);h=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c}),i=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c,morphTargets:!0}),j=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c,skinning:!0}),k=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c,morphTargets:!0,skinning:!0}),h._shadowPass=!0,i._shadowPass=!0,j._shadowPass=!0,k._shadowPass=!0},this.render=function(a,b){g.shadowMapEnabled&&g.shadowMapAutoUpdate&&this.update(a,b)},this.update=function(n,o){var q,r,s,t,u,v,w,x,y,z,A,B,C,D,E=[],F=0,G=null;for(f.clearColor(1,1,1,1),f.disable(f.BLEND),f.enable(f.CULL_FACE),f.frontFace(f.CCW),g.shadowMapCullFace===e.CullFaceFront?f.cullFace(f.FRONT):f.cullFace(f.BACK),g.setDepthTest(!0),q=0,r=n.__lights.length;r>q;q++)if(C=n.__lights[q],C.castShadow)if(C instanceof e.DirectionalLight&&C.shadowCascade)for(u=0;uq;q++){if(C=E[q],!C.shadowMap){var J=e.NearestFilter;g.shadowMapType===e.PCFSoftShadowMap&&(J=e.NearestFilter);var K={minFilter:J,magFilter:J,format:e.RGBAFormat};C.shadowMap=new e.WebGLRenderTarget(C.shadowMapWidth,C.shadowMapHeight,K),C.shadowMapSize=new e.Vector2(C.shadowMapWidth,C.shadowMapHeight),C.shadowMatrix=new e.Matrix4}if(!C.shadowCamera){if(C instanceof e.SpotLight)C.shadowCamera=new e.PerspectiveCamera(C.shadowCameraFov,C.shadowMapWidth/C.shadowMapHeight,C.shadowCameraNear,C.shadowCameraFar);else{if(!(C instanceof e.DirectionalLight)){e.onerror("Unsupported light type for shadow");continue}C.shadowCamera=new e.OrthographicCamera(C.shadowCameraLeft,C.shadowCameraRight,C.shadowCameraTop,C.shadowCameraBottom,C.shadowCameraNear,C.shadowCameraFar)}n.add(C.shadowCamera),n.autoUpdate===!0&&n.updateMatrixWorld()}for(C.shadowCameraVisible&&!C.cameraHelper&&(C.cameraHelper=new e.CameraHelper(C.shadowCamera),C.shadowCamera.add(C.cameraHelper)),C.isVirtual&&H.originalCamera==o&&c(o,C),v=C.shadowMap,w=C.shadowMatrix,x=C.shadowCamera,x.position.setFromMatrixPosition(C.matrixWorld),p.setFromMatrixPosition(C.target.matrixWorld),x.lookAt(p),x.updateMatrixWorld(),x.matrixWorldInverse.getInverse(x.matrixWorld),C.cameraHelper&&(C.cameraHelper.visible=C.shadowCameraVisible),C.shadowCameraVisible&&C.cameraHelper.update(),w.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1),w.multiply(x.projectionMatrix),w.multiply(x.matrixWorldInverse),m.multiplyMatrices(x.projectionMatrix,x.matrixWorldInverse),l.setFromMatrix(m),g.setRenderTarget(v),g.clear(),D=n.__webglObjects,s=0,t=D.length;t>s;s++)A=D[s],B=A.object,A.render=!1,B.visible&&B.castShadow&&((B instanceof e.Mesh||B instanceof e.ParticleSystem)&&B.frustumCulled&&!l.intersectsObject(B)||(B._modelViewMatrix.multiplyMatrices(x.matrixWorldInverse,B.matrixWorld),A.render=!0));var L,M,N;for(s=0,t=D.length;t>s;s++)A=D[s],A.render&&(B=A.object,y=A.buffer,L=d(B),M=void 0!==B.geometry.morphTargets&&B.geometry.morphTargets.length>0&&L.morphTargets,N=B instanceof e.SkinnedMesh&&L.skinning,z=B.customDepthMaterial?B.customDepthMaterial:N?M?k:j:M?i:h,y instanceof e.BufferGeometry?g.renderBufferDirect(x,n.__lights,G,z,y,B):g.renderBuffer(x,n.__lights,G,z,y,B));for(D=n.__webglObjectsImmediate,s=0,t=D.length;t>s;s++)A=D[s],B=A.object,B.visible&&B.castShadow&&(B._modelViewMatrix.multiplyMatrices(x.matrixWorldInverse,B.matrixWorld),g.renderImmediateObject(x,n.__lights,G,h,B))}var O=g.getClearColor(),P=g.getClearAlpha();f.clearColor(O.r,O.g,O.b,P),f.enable(f.BLEND),g.shadowMapCullFace===e.CullFaceFront&&f.cullFace(f.BACK)}},e.ShadowMapPlugin.__projector=new e.Projector,e.SpritePlugin=function(){function a(){var a=c.createProgram(),b=c.createShader(c.VERTEX_SHADER),e=c.createShader(c.FRAGMENT_SHADER);return c.shaderSource(b,["precision "+d.getPrecision()+" float;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform float rotation;","uniform vec2 scale;","uniform vec2 uvOffset;","uniform vec2 uvScale;","attribute vec2 position;","attribute vec2 uv;","varying vec2 vUV;","void main() {","vUV = uvOffset + uv * uvScale;","vec2 alignedPosition = position * scale;","vec2 rotatedPosition;","rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;","rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;","vec4 finalPosition;","finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );","finalPosition.xy += rotatedPosition;","finalPosition = projectionMatrix * finalPosition;","gl_Position = finalPosition;","}"].join("\n")),c.shaderSource(e,["precision "+d.getPrecision()+" float;","uniform vec3 color;","uniform sampler2D map;","uniform float opacity;","uniform int fogType;","uniform vec3 fogColor;","uniform float fogDensity;","uniform float fogNear;","uniform float fogFar;","uniform float alphaTest;","varying vec2 vUV;","void main() {","vec4 texture = texture2D( map, vUV );","if ( texture.a < alphaTest ) discard;","gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );","if ( fogType > 0 ) {","float depth = gl_FragCoord.z / gl_FragCoord.w;","float fogFactor = 0.0;","if ( fogType == 1 ) {","fogFactor = smoothstep( fogNear, fogFar, depth );","} else {","const float LOG2 = 1.442695;","float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );","fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );","}","gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );","}","}"].join("\n")),c.compileShader(b),c.compileShader(e),c.attachShader(a,b),c.attachShader(a,e),c.linkProgram(a),a}function b(a,b){return a.z!==b.z?b.z-a.z:b.id-a.id}var c,d,f,g,h,i,j,k,l,m;this.init=function(b){c=b.context,d=b,g=new Float32Array([-.5,-.5,0,0,.5,-.5,1,0,.5,.5,1,1,-.5,.5,0,1]),h=new Uint16Array([0,1,2,0,2,3]),i=c.createBuffer(),j=c.createBuffer(),c.bindBuffer(c.ARRAY_BUFFER,i),c.bufferData(c.ARRAY_BUFFER,g,c.STATIC_DRAW),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,j),c.bufferData(c.ELEMENT_ARRAY_BUFFER,h,c.STATIC_DRAW),k=a(),l={position:c.getAttribLocation(k,"position"),uv:c.getAttribLocation(k,"uv")},m={uvOffset:c.getUniformLocation(k,"uvOffset"),uvScale:c.getUniformLocation(k,"uvScale"),rotation:c.getUniformLocation(k,"rotation"),scale:c.getUniformLocation(k,"scale"),color:c.getUniformLocation(k,"color"),map:c.getUniformLocation(k,"map"),opacity:c.getUniformLocation(k,"opacity"),modelViewMatrix:c.getUniformLocation(k,"modelViewMatrix"),projectionMatrix:c.getUniformLocation(k,"projectionMatrix"),fogType:c.getUniformLocation(k,"fogType"),fogDensity:c.getUniformLocation(k,"fogDensity"),fogNear:c.getUniformLocation(k,"fogNear"),fogFar:c.getUniformLocation(k,"fogFar"),fogColor:c.getUniformLocation(k,"fogColor"),alphaTest:c.getUniformLocation(k,"alphaTest")};var n=document.createElement("canvas");n.width=8,n.height=8;var o=n.getContext("2d");o.fillStyle="#ffffff",o.fillRect(0,0,n.width,n.height),f=new e.Texture(n),f.needsUpdate=!0},this.render=function(a,g,h,n){var o=a.__webglSprites,p=o.length;if(p){c.useProgram(k),c.enableVertexAttribArray(l.position),c.enableVertexAttribArray(l.uv),c.disable(c.CULL_FACE),c.enable(c.BLEND),c.bindBuffer(c.ARRAY_BUFFER,i),c.vertexAttribPointer(l.position,2,c.FLOAT,!1,16,0),c.vertexAttribPointer(l.uv,2,c.FLOAT,!1,16,8),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,j),c.uniformMatrix4fv(m.projectionMatrix,!1,g.projectionMatrix.elements),c.activeTexture(c.TEXTURE0),c.uniform1i(m.map,0);var q=0,r=0,s=a.fog;s?(c.uniform3f(m.fogColor,s.color.r,s.color.g,s.color.b),s instanceof e.Fog?(c.uniform1f(m.fogNear,s.near),c.uniform1f(m.fogFar,s.far),c.uniform1i(m.fogType,1),q=1,r=1):s instanceof e.FogExp2&&(c.uniform1f(m.fogDensity,s.density),c.uniform1i(m.fogType,2),q=2,r=2)):(c.uniform1i(m.fogType,0),q=0,r=0);var t,u,v,w,x=[];for(t=0;p>t;t++)u=o[t],v=u.material,u.visible!==!1&&(u._modelViewMatrix.multiplyMatrices(g.matrixWorldInverse,u.matrixWorld),u.z=-u._modelViewMatrix.elements[14]);for(o.sort(b),t=0;p>t;t++)u=o[t],u.visible!==!1&&(v=u.material,c.uniform1f(m.alphaTest,v.alphaTest),c.uniformMatrix4fv(m.modelViewMatrix,!1,u._modelViewMatrix.elements),x[0]=u.scale.x,x[1]=u.scale.y,w=a.fog&&v.fog?r:0,q!==w&&(c.uniform1i(m.fogType,w),q=w),null!==v.map?(c.uniform2f(m.uvOffset,v.map.offset.x,v.map.offset.y),c.uniform2f(m.uvScale,v.map.repeat.x,v.map.repeat.y)):(c.uniform2f(m.uvOffset,0,0),c.uniform2f(m.uvScale,1,1)),c.uniform1f(m.opacity,v.opacity),c.uniform3f(m.color,v.color.r,v.color.g,v.color.b),c.uniform1f(m.rotation,v.rotation),c.uniform2fv(m.scale,x),d.setBlending(v.blending,v.blendEquation,v.blendSrc,v.blendDst),d.setDepthTest(v.depthTest),d.setDepthWrite(v.depthWrite),v.map&&v.map.image&&v.map.image.width?d.setTexture(v.map,0):d.setTexture(f,0),c.drawElements(c.TRIANGLES,6,c.UNSIGNED_SHORT,0));c.enable(c.CULL_FACE)}}},e.DepthPassPlugin=function(){function a(a){return a.material instanceof e.MeshFaceMaterial?a.material.materials[0]:a.material}this.enabled=!1,this.renderTarget=null;var b,c,d,f,g,h,i=new e.Frustum,j=new e.Matrix4;this.init=function(a){b=a.context,c=a;var i=e.ShaderLib.depthRGBA,j=e.UniformsUtils.clone(i.uniforms);d=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j}),f=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j,morphTargets:!0}),g=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j,skinning:!0}),h=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j,morphTargets:!0,skinning:!0}),d._shadowPass=!0,f._shadowPass=!0,g._shadowPass=!0,h._shadowPass=!0},this.render=function(a,b){this.enabled&&this.update(a,b)},this.update=function(k,l){var m,n,o,p,q,r,s,t=null;for(b.clearColor(1,1,1,1),b.disable(b.BLEND),c.setDepthTest(!0),k.autoUpdate===!0&&k.updateMatrixWorld(),l.matrixWorldInverse.getInverse(l.matrixWorld),j.multiplyMatrices(l.projectionMatrix,l.matrixWorldInverse),i.setFromMatrix(j),c.setRenderTarget(this.renderTarget),c.clear(),s=k.__webglObjects,m=0,n=s.length;n>m;m++)q=s[m],r=q.object,q.render=!1,r.visible&&((r instanceof e.Mesh||r instanceof e.ParticleSystem)&&r.frustumCulled&&!i.intersectsObject(r)||(r._modelViewMatrix.multiplyMatrices(l.matrixWorldInverse,r.matrixWorld),q.render=!0));var u,v,w;for(m=0,n=s.length;n>m;m++)if(q=s[m],q.render){if(r=q.object,o=q.buffer,r instanceof e.ParticleSystem&&!r.customDepthMaterial)continue;u=a(r),u&&c.setMaterialFaces(r.material),v=r.geometry.morphTargets.length>0&&u.morphTargets,w=r instanceof e.SkinnedMesh&&u.skinning,p=r.customDepthMaterial?r.customDepthMaterial:w?v?h:g:v?f:d,o instanceof e.BufferGeometry?c.renderBufferDirect(l,k.__lights,t,p,o,r):c.renderBuffer(l,k.__lights,t,p,o,r)}for(s=k.__webglObjectsImmediate,m=0,n=s.length;n>m;m++)q=s[m],r=q.object,r.visible&&(r._modelViewMatrix.multiplyMatrices(l.matrixWorldInverse,r.matrixWorld),c.renderImmediateObject(l,k.__lights,t,d,r));var x=c.getClearColor(),y=c.getClearAlpha();b.clearColor(x.r,x.g,x.b,y),b.enable(b.BLEND)}},e.ShaderFlares={lensFlareVertexTexture:{vertexShader:["uniform lowp int renderType;","uniform vec3 screenPosition;","uniform vec2 scale;","uniform float rotation;","uniform sampler2D occlusionMap;","attribute vec2 position;","attribute vec2 uv;","varying vec2 vUV;","varying float vVisibility;","void main() {","vUV = uv;","vec2 pos = position;","if( renderType == 2 ) {","vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );","visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );","visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );","visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );","visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );","visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );","visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );","visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );","visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );","vVisibility = visibility.r / 9.0;","vVisibility *= 1.0 - visibility.g / 9.0;","vVisibility *= visibility.b / 9.0;","vVisibility *= 1.0 - visibility.a / 9.0;","pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;","pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;","}","gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );","}"].join("\n"),fragmentShader:["uniform lowp int renderType;","uniform sampler2D map;","uniform float opacity;","uniform vec3 color;","varying vec2 vUV;","varying float vVisibility;","void main() {","if( renderType == 0 ) {","gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );","} else if( renderType == 1 ) {","gl_FragColor = texture2D( map, vUV );","} else {","vec4 texture = texture2D( map, vUV );","texture.a *= opacity * vVisibility;","gl_FragColor = texture;","gl_FragColor.rgb *= color;","}","}"].join("\n")},lensFlare:{vertexShader:["uniform lowp int renderType;","uniform vec3 screenPosition;","uniform vec2 scale;","uniform float rotation;","attribute vec2 position;","attribute vec2 uv;","varying vec2 vUV;","void main() {","vUV = uv;","vec2 pos = position;","if( renderType == 2 ) {","pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;","pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;","}","gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );","}"].join("\n"),fragmentShader:["precision mediump float;","uniform lowp int renderType;","uniform sampler2D map;","uniform sampler2D occlusionMap;","uniform float opacity;","uniform vec3 color;","varying vec2 vUV;","void main() {","if( renderType == 0 ) {","gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );","} else if( renderType == 1 ) {","gl_FragColor = texture2D( map, vUV );","} else {","float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;","visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;","visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;","visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;","visibility = ( 1.0 - visibility / 4.0 );","vec4 texture = texture2D( map, vUV );","texture.a *= opacity * visibility;","gl_FragColor = texture;","gl_FragColor.rgb *= color;","}","}"].join("\n")}},"undefined"!=typeof c?("undefined"!=typeof b&&b.exports&&(c=b.exports=e),c.THREE=e):this.THREE=e},{}],13:[function(a,b,c){void 0===Date.now&&(Date.now=function(){return(new Date).valueOf()});var d=d||function(){var a=[];return{REVISION:"13",getAll:function(){return a},removeAll:function(){a=[]},add:function(b){a.push(b)},remove:function(b){var c=a.indexOf(b);-1!==c&&a.splice(c,1)},update:function(b){if(0===a.length)return!1;var c=0;for(b=void 0!==b?b:"undefined"!=typeof window&&void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now();ca;a++)p[a].stop()},this.delay=function(a){return l=a,this},this.repeat=function(a){return h=a,this},this.yoyo=function(a){return i=a,this},this.easing=function(a){return n=a,this},this.interpolation=function(a){return o=a,this},this.chain=function(){return p=arguments,this},this.onStart=function(a){return q=a,this},this.onUpdate=function(a){return s=a,this},this.onComplete=function(a){return t=a,this},this.onStop=function(a){return u=a,this},this.update=function(a){var d;if(m>a)return!0;r===!1&&(null!==q&&q.call(b),r=!0);var j=(a-m)/g;j=j>1?1:j;var u=n(j);for(d in e){var v=c[d]||0,w=e[d];w instanceof Array?b[d]=o(w,u):("string"==typeof w&&(w=v+parseFloat(w,10)),"number"==typeof w&&(b[d]=v+(w-v)*u))}if(null!==s&&s.call(b,u),1==j){if(h>0){isFinite(h)&&h--;for(d in f){if("string"==typeof e[d]&&(f[d]=f[d]+parseFloat(e[d],10)),i){var x=f[d];f[d]=e[d],e[d]=x}c[d]=f[d]}return i&&(k=!k),m=a+l,!0}null!==t&&t.call(b);for(var y=0,z=p.length;z>y;y++)p[y].start(a);return!1}return!0}},d.Easing={Linear:{None:function(a){return a}},Quadratic:{In:function(a){return a*a},Out:function(a){return a*(2-a)},InOut:function(a){return(a*=2)<1?.5*a*a:-.5*(--a*(a-2)-1)}},Cubic:{In:function(a){return a*a*a},Out:function(a){return--a*a*a+1},InOut:function(a){return(a*=2)<1?.5*a*a*a:.5*((a-=2)*a*a+2)}},Quartic:{In:function(a){return a*a*a*a},Out:function(a){return 1- --a*a*a*a},InOut:function(a){return(a*=2)<1?.5*a*a*a*a:-.5*((a-=2)*a*a*a-2)}},Quintic:{In:function(a){return a*a*a*a*a},Out:function(a){return--a*a*a*a*a+1},InOut:function(a){return(a*=2)<1?.5*a*a*a*a*a:.5*((a-=2)*a*a*a*a+2)}},Sinusoidal:{In:function(a){return 1-Math.cos(a*Math.PI/2)},Out:function(a){return Math.sin(a*Math.PI/2)},InOut:function(a){return.5*(1-Math.cos(Math.PI*a))}},Exponential:{In:function(a){return 0===a?0:Math.pow(1024,a-1)},Out:function(a){return 1===a?1:1-Math.pow(2,-10*a)},InOut:function(a){return 0===a?0:1===a?1:(a*=2)<1?.5*Math.pow(1024,a-1):.5*(-Math.pow(2,-10*(a-1))+2)}},Circular:{In:function(a){return 1-Math.sqrt(1-a*a)},Out:function(a){return Math.sqrt(1- --a*a)},InOut:function(a){return(a*=2)<1?-.5*(Math.sqrt(1-a*a)-1):.5*(Math.sqrt(1-(a-=2)*a)+1)}},Elastic:{In:function(a){var b,c=.1,d=.4;return 0===a?0:1===a?1:(!c||1>c?(c=1,b=d/4):b=d*Math.asin(1/c)/(2*Math.PI),-(c*Math.pow(2,10*(a-=1))*Math.sin((a-b)*(2*Math.PI)/d)))},Out:function(a){var b,c=.1,d=.4;return 0===a?0:1===a?1:(!c||1>c?(c=1,b=d/4):b=d*Math.asin(1/c)/(2*Math.PI),c*Math.pow(2,-10*a)*Math.sin((a-b)*(2*Math.PI)/d)+1)},InOut:function(a){var b,c=.1,d=.4;return 0===a?0:1===a?1:(!c||1>c?(c=1,b=d/4):b=d*Math.asin(1/c)/(2*Math.PI),(a*=2)<1?-.5*(c*Math.pow(2,10*(a-=1))*Math.sin((a-b)*(2*Math.PI)/d)):c*Math.pow(2,-10*(a-=1))*Math.sin((a-b)*(2*Math.PI)/d)*.5+1)}},Back:{In:function(a){var b=1.70158;return a*a*((b+1)*a-b)},Out:function(a){var b=1.70158;return--a*a*((b+1)*a+b)+1},InOut:function(a){var b=2.5949095;return(a*=2)<1?.5*(a*a*((b+1)*a-b)):.5*((a-=2)*a*((b+1)*a+b)+2)}},Bounce:{In:function(a){return 1-d.Easing.Bounce.Out(1-a)},Out:function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375},InOut:function(a){return.5>a?.5*d.Easing.Bounce.In(2*a):.5*d.Easing.Bounce.Out(2*a-1)+.5}}},d.Interpolation={Linear:function(a,b){var c=a.length-1,e=c*b,f=Math.floor(e),g=d.Interpolation.Utils.Linear;return 0>b?g(a[0],a[1],e):b>1?g(a[c],a[c-1],c-e):g(a[f],a[f+1>c?c:f+1],e-f)},Bezier:function(a,b){var c,e=0,f=a.length-1,g=Math.pow,h=d.Interpolation.Utils.Bernstein;for(c=0;f>=c;c++)e+=g(1-b,f-c)*g(b,c)*a[c]*h(f,c);return e},CatmullRom:function(a,b){var c=a.length-1,e=c*b,f=Math.floor(e),g=d.Interpolation.Utils.CatmullRom;return a[0]===a[c]?(0>b&&(f=Math.floor(e=c*(1+b))),g(a[(f-1+c)%c],a[f],a[(f+1)%c],a[(f+2)%c],e-f)):0>b?a[0]-(g(a[0],a[0],a[1],a[1],-e)-a[0]):b>1?a[c]-(g(a[c],a[c],a[c-1],a[c-1],e-c)-a[c]):g(a[f?f-1:0],a[f],a[f+1>c?c:f+1],a[f+2>c?c:f+2],e-f)},Utils:{Linear:function(a,b,c){return(b-a)*c+a},Bernstein:function(a,b){var c=d.Interpolation.Utils.Factorial;return c(a)/c(b)/c(a-b)},Factorial:function(){var a=[1];return function(b){var c,d=1;if(a[b])return a[b];for(c=b;c>1;c--)d*=c;return a[b]=d}}(),CatmullRom:function(a,b,c,d,e){var f=.5*(c-a),g=.5*(d-b),h=e*e,i=e*h;return(2*b-2*c+f+g)*i+(-3*b+3*c-2*f-g)*h+f*e+b}}},b.exports=d},{}],14:[function(a,b,c){!function d(a,c,e){function f(a,b){return this instanceof f?(g(a)?(b=a[1],a=a[0]):"object"==typeof a&&a&&(b=a.y,a=a.x),this.x=f.clean(a||0),void(this.y=f.clean(b||0))):new f(a,b)}var g=function(a){return"[object Array]"===Object.prototype.toString.call(a)};f.prototype={change:function(a){if("function"==typeof a)this.observers?this.observers.push(a):this.observers=[a];else if(this.observers&&this.observers.length)for(var b=this.observers.length-1;b>=0;b--)this.observers[b](this,a);return this},ignore:function(a){if(this.observers)if(a)for(var b=this.observers,c=b.length;c--;)b[c]===a&&b.splice(c,1);else this.observers=[];return this},set:function(a,b,c){if("number"!=typeof a&&(c=b,b=a.y,a=a.x),this.x===a&&this.y===b)return this;var d=null;return c!==!1&&this.observers&&this.observers.length&&(d=this.clone()),this.x=f.clean(a),this.y=f.clean(b),c!==!1?this.change(d):void 0; -},zero:function(){return this.set(0,0)},clone:function(){return new this.constructor(this.x,this.y)},negate:function(a){return a?new this.constructor(-this.x,-this.y):this.set(-this.x,-this.y)},add:function(a,b,c){return"number"!=typeof a&&(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)),a+=this.x,b+=this.y,c?new this.constructor(a,b):this.set(a,b)},subtract:function(a,b,c){return"number"!=typeof a&&(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)),a=this.x-a,b=this.y-b,c?new this.constructor(a,b):this.set(a,b)},multiply:function(a,b,c){return"number"!=typeof a?(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)):"number"!=typeof b&&(c=b,b=a),a*=this.x,b*=this.y,c?new this.constructor(a,b):this.set(a,b)},rotate:function(a,b,c){var d,e,f=this.x,g=this.y,h=Math.cos(a),i=Math.sin(a);return b=b?-1:1,d=h*f-b*i*g,e=b*i*f+h*g,c?new this.constructor(d,e):this.set(d,e)},length:function(){var a=this.x,b=this.y;return Math.sqrt(a*a+b*b)},lengthSquared:function(){var a=this.x,b=this.y;return a*a+b*b},distance:function(a){var b=this.x-a.x,c=this.y-a.y;return Math.sqrt(b*b+c*c)},normalize:function(a){var b=this.length(),c=bc?c:e,h=f>d?d:f;return b?new this.constructor(g,h):this.set(g,h)},max:function(a,b){var c=this.x,d=this.y,e=a.x,f=a.y,g=c>e?c:e,h=d>f?d:f;return b?new this.constructor(g,h):this.set(g,h)},clamp:function(a,b,c){var d=this.min(b,!0).max(a);return c?d:this.set(d.x,d.y)},lerp:function(a,b,c){return this.add(a.subtract(this,!0).multiply(b),c)},skew:function(a){return a?new this.constructor(-this.y,this.x):this.set(-this.y,this.x)},dot:function(a){return f.clean(this.x*a.x+a.y*this.y)},perpDot:function(a){return f.clean(this.x*a.y-this.y*a.x)},angleTo:function(a){return Math.atan2(this.perpDot(a),this.dot(a))},divide:function(a,b,c){if("number"!=typeof a?(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)):"number"!=typeof b&&(c=b,b=a),0===a||0===b)throw new Error("division by zero");if(isNaN(a)||isNaN(b))throw new Error("NaN detected");return c?new this.constructor(this.x/a,this.y/b):this.set(this.x/a,this.y/b)},isPointOnLine:function(a,b){return(a.y-this.y)*(a.x-b.x)===(a.y-b.y)*(a.x-this.x)},toArray:function(){return[this.x,this.y]},fromArray:function(a){return this.set(a[0],a[1])},toJSON:function(){return{x:this.x,y:this.y}},toString:function(){return"("+this.x+", "+this.y+")"},constructor:f},f.fromArray=function(a,b){return new(b||f)(a[0],a[1])},f.precision=c||8;var h=Math.pow(10,f.precision);return f.clean=a||function(a){if(isNaN(a))throw new Error("NaN detected");if(!isFinite(a))throw new Error("Infinity detected");return Math.round(a)===a?a:Math.round(a*h)/h},f.inject=d,a||(f.fast=d(function(a){return a}),"undefined"!=typeof b&&"object"==typeof b.exports?b.exports=f:window.Vec2=window.Vec2||f),f}()},{}],15:[function(a,b,c){function d(a,b,c){c||(c={}),this.width=a,this.height=b,this.points=[],this.introLines=new f.Object3D,this.pins=[],this.markers=[],this.satelliteAnimations=[],this.satelliteMeshes=[],this.satellites={},this.quadtree=new g(new h(180,360),5),this.active=!0;var d={font:"Inconsolata",baseColor:"#ffcc00",markerColor:"#ffcc00",pinColor:"#00eeee",satelliteColor:"#ff0000",introLinesAltitude:1.1,introLinesDuration:2e3,introLinesColor:"#8FD8D8",introLinesCount:60,scale:1,dayLength:28e3,maxPins:500,maxMarkers:4,data:[],tiles:[],viewAngle:.1,cameraAngle:Math.PI};for(var e in d)this[e]||(this[e]=d[e],void 0!==c[e]&&(this[e]=c[e]));0===this.dayLength?this.rotationSpeed=0:this.rotationSpeed=1e3/this.dayLength,this.setScale(this.scale),this.renderer=new f.WebGLRenderer({antialias:!0}),this.renderer.setSize(this.width,this.height),this.renderer.gammaInput=!0,this.renderer.gammaOutput=!0,this.domElement=this.renderer.domElement,this.data.sort(function(a,b){return b.lng-2*b.label.length-(a.lng-2*a.label.length)});for(var e=0;e0&&this.firstRunTime+(next=this.data.pop()).when=Date.now()&&this.data.push(next)}},q=function(){this.hexGrid&&this.scene.remove(this.hexGrid);var a=["#define PI 3.141592653589793238462643","#define DISTANCE 500.0","#define INTRODURATION "+(parseFloat(this.introLinesDuration)+1e-5),"#define INTROALTITUDE "+(parseFloat(this.introLinesAltitude)+1e-5),"attribute float lng;","uniform float currentTime;","varying vec4 vColor;","","void main()","{"," vec3 newPos = position;"," float opacityVal = 0.0;"," float introStart = INTRODURATION * ((180.0 + lng)/360.0);"," if(currentTime > introStart){"," opacityVal = 1.0;"," }"," if(currentTime > introStart && currentTime < introStart + INTRODURATION / 8.0){"," newPos = position * INTROALTITUDE;"," opacityVal = .3;"," }"," if(currentTime > introStart + INTRODURATION / 8.0 && currentTime < introStart + INTRODURATION / 8.0 + 200.0){"," newPos = position * (1.0 + ((INTROALTITUDE-1.0) * (1.0-(currentTime - introStart-(INTRODURATION/8.0))/200.0)));"," }"," vColor = vec4( color, opacityVal );"," gl_Position = projectionMatrix * modelViewMatrix * vec4(newPos, 1.0);","}"].join("\n"),b=["varying vec4 vColor;","void main()","{"," gl_FragColor = vColor;"," float depth = gl_FragCoord.z / gl_FragCoord.w;"," float fogFactor = smoothstep("+parseInt(this.cameraDistance)+".0,"+parseInt(this.cameraDistance+300)+".0, depth );"," vec3 fogColor = vec3(0.0);"," gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w ), fogFactor );","}"].join("\n"),c={lng:{type:"f",value:null}};this.pointUniforms={currentTime:{type:"f",value:0}};var d=new f.ShaderMaterial({uniforms:this.pointUniforms,attributes:c,vertexShader:a,fragmentShader:b,transparent:!0,vertexColors:f.VertexColors,side:f.DoubleSide}),e=4*this.tiles.length,g=new f.BufferGeometry;g.addAttribute("index",Uint16Array,3*e,1),g.addAttribute("position",Float32Array,3*e,3),g.addAttribute("normal",Float32Array,3*e,3),g.addAttribute("color",Float32Array,3*e,3),g.addAttribute("lng",Float32Array,3*e,1);for(var h=g.attributes.lng.array,i=m(this.baseColor).hueSet(),j=[],k=0;k5&&q(s+3,r.b[0].x,r.b[0].y,r.b[0].z,r.b[5].x,r.b[5].y,r.b[5].z,r.b[4].x,r.b[4].y,r.b[4].z,r.lat,r.lon,v)}g.offsets=[];for(var w=e/l,k=0;w>k;k++){var x={start:k*l*3,index:k*l*3,count:3*Math.min(e-k*l,l)};g.offsets.push(x)}g.computeBoundingSphere(),this.hexGrid=new f.Mesh(g,d),this.scene.add(this.hexGrid)},r=function(){for(var a,b=new f.LineBasicMaterial({color:this.introLinesColor,transparent:!0,linewidth:2,opacity:.5}),c=0;ci;i++){var j=n.mapPoint(e,g-5*i);a=new f.Vector3(j.x*this.introLinesAltitude,j.y*this.introLinesAltitude,j.z*this.introLinesAltitude),d.vertices.push(a)}this.introLines.add(new f.Line(d,b))}this.scene.add(this.introLines)},s=function(a){var b,c=!1,d=0,e=Date.now(),g=!1,h=new f.Vector3(0,0,0),i=new f.Projector;a.domElement.onmousedown=function(a){c=!0,d=a.clientX,e=Date.now(),g=!1},a.domElement.onmouseup=function(b){c=!1,a.resetRotationSpeed()},a.domElement.onmouseleave=function(b){c=!1,a.resetRotationSpeed()};var j=function(f,i){h.x=2*(f.clientX/a.width)-1,h.y=1-2*(f.clientY/a.height);var k=Date.now()-e;c&&k&&(g=!0,a.setRotationSpeed((f.clientX-d)/a.width/(k/1e3)),e=Date.now(),d=f.clientX,clearTimeout(b),i||(b=setTimeout(function(){j(f,!0)},100)))},k=function(b){if(!g){for(var c=i.pickingRay(h.clone(),a.camera),d=c.intersectObjects(a.scene.children),e=1.1*a.cameraDistance,f=null,j=0;j0)){var k=a.camera.position.distanceTo(d[j].object.position);e>k&&(e=k,f=objName)}null!=f&&a.clickHandler&&a.clickHandler(f)}};a.domElement.onmousemove=j,a.domElement.onclick=k};d.prototype.init=function(a){this.camera=new f.PerspectiveCamera(50,this.width/this.height,1,this.cameraDistance+300),this.camera.position.z=this.cameraDistance,this.scene=new f.Scene,this.scene.fog=new f.Fog(0,this.cameraDistance,this.cameraDistance+300),r.call(this),this.smokeProvider=new l(this.scene),q.call(this),setTimeout(a,500)},d.prototype.destroy=function(a){var b=this;this.active=!1,setTimeout(function(){for(;b.scene.children.length>0;)b.scene.remove(b.scene.children[0]);"function"==typeof a&&a()},1e3)},d.prototype.addPin=function(a,b,c,d){a=parseFloat(a),b=parseFloat(b);var e={lineColor:this.pinColor,topColor:this.pinColor,font:this.font,id:d},f=1.2;"string"==typeof c&&0!==c.length||(f-=.05+.05*Math.random());var g=new i(a,b,c,f,this.scene,this.smokeProvider,e);this.pins.push(g);var j=o(a,b);if(g.pos_=new h(parseInt(j.x),parseInt(j.y)),c.length>0?g.rad_=j.rad:g.rad_=1,this.quadtree.addObject(g),c.length>0){var k=this.quadtree.getCollisionsForObject(g),l=0,m=0,n=[];for(var p in k)k[p].text.length>0&&(l++,k[p].age()>5e3?n.push(k[p]):m++);if(l>0&&0==m)for(var p=0;p0&&(g.hideLabel(),g.hideSmoke(),g.hideTop(),g.changeAltitude(.05*Math.random()+1.1))}if(this.pins.length>this.maxPins){var q=this.pins.shift();this.quadtree.removeObject(q),q.remove()}return g},d.prototype.addMarker=function(a,b,c,d){var e,f={markerColor:this.markerColor,lineColor:this.markerColor,font:this.font};return e="boolean"==typeof d&&d?new j(a,b,c,1.2,this.markers[this.markers.length-1],this.scene,f):"object"==typeof d?new j(a,b,c,1.2,d,this.scene,f):new j(a,b,c,1.2,null,this.scene,f),this.markers.push(e),this.markers.length>this.maxMarkers&&this.markers.shift().remove(),e},d.prototype.addSatellite=function(a,b,c,d,e,f){d||(d={}),void 0==d.coreColor&&(d.coreColor=this.satelliteColor);var g=new k(a,b,c,this.scene,d,e,f);return this.satellites[g.toString()]||(this.satellites[g.toString()]=g),g.onRemove(function(){delete this.satellites[g.toString()]}.bind(this)),g},d.prototype.addConstellation=function(a,b){for(var c,d=[],e=0;ethis.maxPins;){var b=this.pins.shift();this.quadtree.removeObject(b),b.remove()}},d.prototype.setMaxMarkers=function(a){for(this.maxMarkers=a;this.markers.length>this.maxMarkers;)this.markers.shift().remove()},d.prototype.setBaseColor=function(a){this.baseColor=a,q.call(this)},d.prototype.setMarkerColor=function(a){this.markerColor=a,this.scene._encom_markerTexture=null},d.prototype.setPinColor=function(a){this.pinColor=a},d.prototype.setScale=function(a){this.scale=a,this.cameraDistance=1700/a,this.scene&&this.scene.fog&&(this.scene.fog.near=this.cameraDistance,this.scene.fog.far=this.cameraDistance+300,q.call(this),this.camera.far=this.cameraDistance+300,this.camera.updateProjectionMatrix())},d.prototype.setRotationSpeed=function(a){this.rotationSpeed=a},d.prototype.resetRotationSpeed=function(){this.rotationSpeed=this.defaultRotationSpeed},d.prototype.tick=function(){if(this.camera){this.firstRunTime||(this.firstRunTime=Date.now()),p.call(this),e.update(),this.lastRenderDate||(this.lastRenderDate=new Date),this.firstRenderDate||(this.firstRenderDate=new Date),this.totalRunTime=new Date-this.firstRenderDate;var a=new Date-this.lastRenderDate;this.lastRenderDate=new Date;var b=this.rotationSpeed*a/1e3*2*Math.PI;this.cameraAngle+=b,this.active||(this.cameraDistance+=1e3*a/1e3),this.camera.position.x=this.cameraDistance*Math.cos(this.cameraAngle)*Math.cos(this.viewAngle),this.camera.position.y=Math.sin(this.viewAngle)*this.cameraDistance,this.camera.position.z=this.cameraDistance*Math.sin(this.cameraAngle)*Math.cos(this.viewAngle);for(var c in this.satellites)this.satellites[c].tick(this.camera.position,this.cameraAngle,a);for(var c=0;cthis.totalRunTime?(this.totalRunTime/this.introLinesDuration<.1&&(this.introLines.children[0].material.opacity=this.totalRunTime/this.introLinesDuration*10-.2),this.totalRunTime/this.introLinesDuration>.8?this.introLines.children[0].material.opacity=5*Math.max(1-this.totalRunTime/this.introLinesDuration,0):this.introLines.children[0].material.opacity=1,this.introLines.rotateY(2*Math.PI/(this.introLinesDuration/a))):this.introLines&&(this.scene.remove(this.introLines),delete[this.introLines]),this.pointUniforms.currentTime.value=this.totalRunTime,this.smokeProvider.tick(this.totalRunTime),this.camera.lookAt(this.scene.position),this.renderer.render(this.scene,this.camera)}},d.prototype.setClickHandler=function(a){this.clickHandler=a},b.exports=d},{"./Marker":16,"./Pin":17,"./Satellite":18,"./SmokeProvider":19,"./utils":21,"hexasphere.js":3,"pusher.color":6,quadtree2:8,three:12,"tween.js":13,vec2:14}],16:[function(a,b,c){var d=a("three"),e=a("tween.js"),f=a("./utils"),g=function(a){var b,c,e=30,g=30;return b=f.renderToCanvas(e,g,function(b){b.fillStyle=a,b.strokeStyle=a,b.lineWidth=3,b.beginPath(),b.arc(e/2,g/2,e/3,0,2*Math.PI),b.stroke(),b.beginPath(),b.arc(e/2,g/2,e/5,0,2*Math.PI),b.fill()}),c=new d.Texture(b),c.needsUpdate=!0,c},h=function(a,b,c,h,i,j,k){var l,m,n,o,p,q,r={lineColor:"#FFCC00",lineWidth:1,markerColor:"#FFCC00",labelColor:"#FFF",font:"Inconsolata",fontSize:20,drawTime:2e3,lineSegments:150};if(this.lat=parseFloat(a),this.lon=parseFloat(b),this.text=c,this.altitude=parseFloat(h),this.scene=j,this.previous=i,this.next=[],this.previous&&this.previous.next.push(this),k)for(var s in r)void 0!=k[s]&&(r[s]=k[s]);this.opts=r,l=f.mapPoint(a,b),i&&(m=f.mapPoint(i.lat,i.lon)),j._encom_markerTexture||(j._encom_markerTexture=g(this.opts.markerColor)),n=new d.SpriteMaterial({map:j._encom_markerTexture,opacity:.7,depthTest:!0,fog:!0}),this.marker=new d.Sprite(n),this.marker.scale.set(0,0),this.marker.position.set(l.x*h,l.y*h,l.z*h),o=f.createLabel(c.toUpperCase(),this.opts.fontSize,this.opts.labelColor,this.opts.font,this.opts.markerColor),p=new d.Texture(o),p.needsUpdate=!0,q=new d.SpriteMaterial({map:p,useScreenCoordinates:!1,opacity:0,depthTest:!0,fog:!0}),this.labelSprite=new d.Sprite(q),this.labelSprite.position={x:l.x*h*1.1,y:l.y*h*1.05+(l.y<0?-15:30),z:l.z*h*1.1},this.labelSprite.scale.set(o.width,o.height),new e.Tween({opacity:0}).to({opacity:1},500).onUpdate(function(){q.opacity=this.opacity}).start();var t=this;if(new e.Tween({x:0,y:0}).to({x:50,y:50},2e3).easing(e.Easing.Elastic.Out).onUpdate(function(){t.marker.scale.set(this.x,this.y)}).delay(this.previous?t.opts.drawTime:0).start(),this.previous){var u,v,w,x,y,z,A,B,C,D,E,F,G=[],H=[];t.geometrySpline=new d.Geometry,u=new d.LineBasicMaterial({color:this.opts.lineColor,transparent:!0,linewidth:3,opacity:.5}),t.geometrySplineDotted=new d.Geometry,v=new d.LineBasicMaterial({color:this.opts.lineColor,linewidth:1,transparent:!0,opacity:.5}),w=(a-i.lat)/t.opts.lineSegments,x=(b-i.lon)/t.opts.lineSegments,y=f.mapPoint(i.lat,i.lon),G=[],H=[];for(var I=0;I=a.index&&(E.set(1.2*D.x,1.2*D.y,1.2*D.z),currentVert2.set(1.19*currentPoint2.x,1.19*currentPoint2.y,1.19*currentPoint2.z)),t.geometrySpline.verticesNeedUpdate=!0,t.geometrySplineDotted.verticesNeedUpdate=!0;G.length>0&&setTimeout(F,t.opts.drawTime/t.opts.lineSegments)},F(),this.scene.add(new d.Line(t.geometrySpline,u)),this.scene.add(new d.Line(t.geometrySplineDotted,v,d.LinePieces))}this.scene.add(this.marker),this.scene.add(this.labelSprite)};h.prototype.remove=function(){for(var a=0,b=this,c=function(d){for(var e=0;a>e;e++)d.geometrySpline.vertices[e].set(d.geometrySpline.vertices[e+1]),d.geometrySplineDotted.vertices[e].set(d.geometrySplineDotted.vertices[e+1]),d.geometrySpline.verticesNeedUpdate=!0,d.geometrySplineDotted.verticesNeedUpdate=!0;a++,a0,showTop:c.length>0,showSmoke:c.length>0,id:null};if(this.lat=a,this.lon=b,this.text=c,this.altitude=h,this.scene=i,this.smokeProvider=j,this.dateCreated=Date.now(),k)for(var t in s)void 0!=k[t]&&(s[t]=k[t]);this.opts=s,this.topVisible=s.showTop,this.smokeVisible=s.showSmoke,this.labelVisible=s.showLabel,this.lineGeometry=new d.Geometry,l=new d.LineBasicMaterial({color:s.lineColor,linewidth:s.lineWidth}),r=f.mapPoint(a,b),this.lineGeometry.vertices.push(new d.Vector3(r.x,r.y,r.z)),this.lineGeometry.vertices.push(new d.Vector3(r.x,r.y,r.z)),this.line=new d.Line(this.lineGeometry,l),m=f.createLabel(c,18,s.labelColor,s.font),n=new d.Texture(m),n.needsUpdate=!0,o=new d.SpriteMaterial({map:n,useScreenCoordinates:!1,opacity:0,depthTest:!0,fog:!0}),this.labelSprite=new d.Sprite(o),this.labelSprite.position={x:r.x*h*1.1,y:r.y*h+(r.y<0?-15:30),z:r.z*h*1.1},this.labelSprite.scale.set(m.width,m.height),p=new d.Texture(g(s.topColor)),p.needsUpdate=!0,q=new d.SpriteMaterial({map:p,depthTest:!0,fog:!0,opacity:0}),this.topSprite=new d.Sprite(q),this.topSprite.scale.set(20,20),this.topSprite.position.set(r.x*h,r.y*h,r.z*h),this.smokeVisible&&(this.smokeId=j.setFire(a,b,h));var u=this;(s.showTop||s.showLabel)&&new e.Tween({opacity:0}).to({opacity:1},500).onUpdate(function(){u.topVisible?q.opacity=this.opacity:q.opacity=0,u.labelVisible?o.opacity=this.opacity:o.opacity=0}).delay(1e3).start(),new e.Tween(r).to({x:r.x*h,y:r.y*h,z:r.z*h},1500).easing(e.Easing.Elastic.Out).onUpdate(function(){u.lineGeometry.vertices[1].x=this.x,u.lineGeometry.vertices[1].y=this.y,u.lineGeometry.vertices[1].z=this.z,u.lineGeometry.verticesNeedUpdate=!0}).start(),null!==this.opts.id&&void 0!==this.opts.id&&(this.labelSprite.name=this.opts.id,this.line.name=this.opts.id,this.topSprite.name=this.opts.id),this.scene.add(this.labelSprite),this.scene.add(this.line),this.scene.add(this.topSprite)};h.prototype.toString=function(){return""+this.lat+"_"+this.lon},h.prototype.changeAltitude=function(a){var b=f.mapPoint(this.lat,this.lon),c=this;new e.Tween({altitude:this.altitude}).to({altitude:a},1500).easing(e.Easing.Elastic.Out).onUpdate(function(){c.smokeVisible&&c.smokeProvider.changeAltitude(this.altitude,c.smokeId),c.topVisible&&c.topSprite.position.set(b.x*this.altitude,b.y*this.altitude,b.z*this.altitude),c.labelVisible&&(c.labelSprite.position={x:b.x*this.altitude*1.1,y:b.y*this.altitude+(b.y<0?-15:30),z:b.z*this.altitude*1.1}),c.lineGeometry.vertices[1].x=b.x*this.altitude,c.lineGeometry.vertices[1].y=b.y*this.altitude,c.lineGeometry.vertices[1].z=b.z*this.altitude,c.lineGeometry.verticesNeedUpdate=!0}).onComplete(function(){c.altitude=a}).start()},h.prototype.hideTop=function(){this.topVisible&&(this.topSprite.material.opacity=0,this.topVisible=!1)},h.prototype.showTop=function(){this.topVisible||(this.topSprite.material.opacity=1,this.topVisible=!0)},h.prototype.hideLabel=function(){this.labelVisible&&(this.labelSprite.material.opacity=0,this.labelVisible=!1)},h.prototype.showLabel=function(){this.labelVisible||(this.labelSprite.material.opacity=1,this.labelVisible=!0)},h.prototype.hideSmoke=function(){this.smokeVisible&&(this.smokeProvider.extinguish(this.smokeId),this.smokeVisible=!1)},h.prototype.showSmoke=function(){this.smokeVisible||(this.smokeId=this.smokeProvider.setFire(this.lat,this.lon,this.altitude),this.smokeVisible=!0)},h.prototype.age=function(){return Date.now()-this.dateCreated},h.prototype.remove=function(){this.scene.remove(this.labelSprite),this.scene.remove(this.line),this.scene.remove(this.topSprite),this.smokeVisible&&this.smokeProvider.extinguish(this.smokeId)},b.exports=h},{"./utils":21,three:12,"tween.js":13}],18:[function(a,b,c){var d=a("./TextureAnimator"),e=a("three"),f=a("./utils"),g=function(a,b,c,d,e,g,h,i){var j=a/c,k=Math.floor((a-d)/e),l=b-25,m=l/(a-d),n=0,o=0,p=0,q=f.hexToRgb(g);return f.renderToCanvas(a*b/c,b*c,function(c){for(var f=0;a>f;f++){f-p*j>=j&&(n=0,o+=b,p++);var g=n+25,l=o+Math.floor(b/2);c.lineWidth=2,c.strokeStyle=i;var r=Math.PI/16,s=-Math.PI+Math.PI/4,t=8,u=Math.floor(a-2*(a-d)/e)+1;d>f&&(t=t*f/d);for(var v=Math.floor((u-d)/2)+d,w=0;4>w;w++){if(c.beginPath(),d>f||f>=a)c.arc(g,l,t,w*Math.PI/2+s+r,w*Math.PI/2+s+Math.PI/2-2*r);else if(f>d&&v>f){var x=v-d,y=3*Math.PI/2,z=f-d,A=y/x,B=-Math.PI+Math.PI/4+r+A*z;c.arc(g,l,t,Math.max(w*Math.PI/2+s,B),Math.max(w*Math.PI/2+s+Math.PI/2-2*r,B+Math.PI/2-2*r))}else if(f>=v&&u>f){var x=u-v,y=2*w*Math.PI/4,z=f-v,A=y/x,B=Math.PI/2+Math.PI/4+r+A*z;c.arc(g,l,t,B,B+Math.PI/2-2*r)}else if(f>=u&&(a-u)/2+u>f){var x=(a-u)/2,y=Math.PI/2,z=f-u,A=y/x,B=w*(Math.PI/2)+Math.PI/4+r+A*z;c.arc(g,l,t,B,B+Math.PI/2-2*r)}else c.arc(g,l,t,w*Math.PI/2+s+r,w*Math.PI/2+s+Math.PI/2-2*r);c.stroke()}for(var C,D=0;e>D;D++)C=f-k*D-d,C>0&&b-25>C*m&&(c.strokeStyle="rgba("+q.r+","+q.g+","+q.b+","+(.9-C*m/(b-25))+")",c.lineWidth=2,c.beginPath(),c.arc(g,l,C*m,-Math.PI/12,Math.PI/12),c.stroke());c.fillStyle="#000",c.beginPath(),c.arc(g,l,3,0,2*Math.PI),c.fill(),c.strokeStyle=h,c.lineWidth=2,c.beginPath(),d>f?c.arc(g,l,3*f/d,0,2*Math.PI):c.arc(g,l,3,0,2*Math.PI),c.stroke(),n+=b}})},h=function(a,b,c,h,i,j,k){var l,m,n,o,p,q,r,s=f.mapPoint(a,b);s.x*=c,s.y*=c,s.z*=c;var m={numWaves:8,waveColor:"#FFF",coreColor:"#FF0000",shieldColor:"#FFF",size:1};if(this.lat=a,this.lon=b,this.altitude=c,this.scene=h,this.onRemoveList=[],n=50,o=100,p=10,q=Math.floor(n/8),i)for(var t in m)void 0!=i[t]&&(m[t]=i[t]);this.opts=m,j?(this.canvas=j,k?this.texture=k:(this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,r=Math.floor(n-2*(n-q)/m.numWaves)+1,this.animator=new d(this.texture,p,n/p,n,80,r))):(this.canvas=g(n,o,p,q,m.numWaves,m.waveColor,m.coreColor,m.shieldColor),this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,r=Math.floor(n-2*(n-q)/m.numWaves)+1,this.animator=new d(this.texture,p,n/p,n,80,r)),l=new e.PlaneGeometry(150*m.size,150*m.size,1,1),this.material=new e.MeshBasicMaterial({map:this.texture,depthTest:!1,transparent:!0}),this.mesh=new e.Mesh(l,this.material),this.mesh.tiltMultiplier=Math.PI/2*(1-Math.abs(a/90)),this.mesh.tiltDirection=a>0?-1:1,this.mesh.lon=b,this.mesh.position.set(s.x,s.y,s.z),this.mesh.rotation.z=-1*(a/90)*Math.PI/2,this.mesh.rotation.y=b/180*Math.PI,h.add(this.mesh)};h.prototype.changeAltitude=function(a){var b=f.mapPoint(this.lat,this.lon);b.x*=a,b.y*=a,b.z*=a,this.altitude=a,this.mesh.position.set(b.x,b.y,b.z)},h.prototype.changeCanvas=function(a,b,c,f){numFrames=50,pixels=100,rows=10,waveStart=Math.floor(numFrames/8),a?this.opts.numWaves=a:a=this.opts.numWaves,b?this.opts.waveColor=b:b=this.opts.waveColor,c?this.opts.coreColor=c:c=this.opts.coreColor,f?this.opts.shieldColor=f:f=this.opts.shieldColor,this.canvas=g(numFrames,pixels,rows,waveStart,a,b,c,f),this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,repeatAt=Math.floor(numFrames-2*(numFrames-waveStart)/a)+1,this.animator=new d(this.texture,rows,numFrames/rows,numFrames,80,repeatAt),this.material.map=this.texture},h.prototype.tick=function(a,b,c){this.mesh.lookAt(a),this.mesh.rotateZ(this.mesh.tiltDirection*Math.PI/2),this.mesh.rotateZ(Math.sin(b+this.mesh.lon/180*Math.PI)*this.mesh.tiltMultiplier*this.mesh.tiltDirection*-1),this.animator&&this.animator.update(c)},h.prototype.remove=function(){this.scene.remove(this.mesh);for(var a=0;a 0.0 && active > 0.0) {"," dt = mod(dt,1500.0);"," }"," float opacity = 1.0 - dt/ 1500.0;"," if (dt == 0.0 || active == 0.0){"," opacity = 0.0;"," }"," vec3 newPos = getPos(myStartLat, myStartLon - ( dt / 50.0));"," vColor = vec4( color, opacity );"," vec4 mvPosition = modelViewMatrix * vec4( newPos, 1.0 );"," gl_PointSize = 2.5 - (dt / 1500.0);"," gl_Position = projectionMatrix * mvPosition;","}"].join("\n"),g=["varying vec4 vColor;","void main()","{"," gl_FragColor = vColor;"," float depth = gl_FragCoord.z / gl_FragCoord.w;"," float fogFactor = smoothstep(1500.0, 1800.0, depth );"," vec3 fogColor = vec3(0.0);"," gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w), fogFactor );","}"].join("\n"),h=function(a,b){var c={smokeCount:5e3,smokePerPin:30,smokePerSecond:20};if(b)for(var e in c)void 0!==b[e]&&(c[e]=b[e]);this.opts=c,this.geometry=new d.Geometry,this.attributes={myStartTime:{type:"f",value:[]},myStartLat:{type:"f",value:[]},myStartLon:{type:"f",value:[]},altitude:{type:"f",value:[]},active:{type:"f",value:[]}},this.uniforms={currentTime:{type:"f",value:0},color:{type:"c",value:new d.Color("#aaa")}};for(var h=new d.ShaderMaterial({uniforms:this.uniforms,attributes:this.attributes,vertexShader:f,fragmentShader:g,transparent:!0}),e=0;ethis.tileDisplayDuration;)if(this.shutDownFlag&&this.currentTile>=e)this.done=!0,this.shutDownCb();else{this.currentDisplayTime-=this.tileDisplayDuration,this.currentTile++,this.currentTile!=e||this.shutDownFlag||(this.currentTile=g);var c=this.currentTile%this.tilesHorizontal;a.offset.x=c/this.tilesHorizontal;var d=Math.floor(this.currentTile/this.tilesHorizontal);a.offset.y=1-d/this.tilesVertical-1/this.tilesVertical}},this.shutDown=function(a){_this.shutDownFlag=!0,_this.shutDownCb=a}};b.exports=e},{three:12}],21:[function(a,b,c){var d={renderToCanvas:function(a,b,c){var d=document.createElement("canvas");return d.width=a,d.height=b,c(d.getContext("2d")),d},mapPoint:function(a,b,c){c||(c=500);var d=(90-a)*Math.PI/180,e=(180-b)*Math.PI/180,f=c*Math.sin(d)*Math.cos(e),g=c*Math.cos(d),h=c*Math.sin(d)*Math.sin(e); +},zero:function(){return this.set(0,0)},clone:function(){return new this.constructor(this.x,this.y)},negate:function(a){return a?new this.constructor(-this.x,-this.y):this.set(-this.x,-this.y)},add:function(a,b,c){return"number"!=typeof a&&(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)),a+=this.x,b+=this.y,c?new this.constructor(a,b):this.set(a,b)},subtract:function(a,b,c){return"number"!=typeof a&&(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)),a=this.x-a,b=this.y-b,c?new this.constructor(a,b):this.set(a,b)},multiply:function(a,b,c){return"number"!=typeof a?(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)):"number"!=typeof b&&(c=b,b=a),a*=this.x,b*=this.y,c?new this.constructor(a,b):this.set(a,b)},rotate:function(a,b,c){var d,e,f=this.x,g=this.y,h=Math.cos(a),i=Math.sin(a);return b=b?-1:1,d=h*f-b*i*g,e=b*i*f+h*g,c?new this.constructor(d,e):this.set(d,e)},length:function(){var a=this.x,b=this.y;return Math.sqrt(a*a+b*b)},lengthSquared:function(){var a=this.x,b=this.y;return a*a+b*b},distance:function(a){var b=this.x-a.x,c=this.y-a.y;return Math.sqrt(b*b+c*c)},normalize:function(a){var b=this.length(),c=bc?c:e,h=f>d?d:f;return b?new this.constructor(g,h):this.set(g,h)},max:function(a,b){var c=this.x,d=this.y,e=a.x,f=a.y,g=c>e?c:e,h=d>f?d:f;return b?new this.constructor(g,h):this.set(g,h)},clamp:function(a,b,c){var d=this.min(b,!0).max(a);return c?d:this.set(d.x,d.y)},lerp:function(a,b,c){return this.add(a.subtract(this,!0).multiply(b),c)},skew:function(a){return a?new this.constructor(-this.y,this.x):this.set(-this.y,this.x)},dot:function(a){return f.clean(this.x*a.x+a.y*this.y)},perpDot:function(a){return f.clean(this.x*a.y-this.y*a.x)},angleTo:function(a){return Math.atan2(this.perpDot(a),this.dot(a))},divide:function(a,b,c){if("number"!=typeof a?(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)):"number"!=typeof b&&(c=b,b=a),0===a||0===b)throw new Error("division by zero");if(isNaN(a)||isNaN(b))throw new Error("NaN detected");return c?new this.constructor(this.x/a,this.y/b):this.set(this.x/a,this.y/b)},isPointOnLine:function(a,b){return(a.y-this.y)*(a.x-b.x)===(a.y-b.y)*(a.x-this.x)},toArray:function(){return[this.x,this.y]},fromArray:function(a){return this.set(a[0],a[1])},toJSON:function(){return{x:this.x,y:this.y}},toString:function(){return"("+this.x+", "+this.y+")"},constructor:f},f.fromArray=function(a,b){return new(b||f)(a[0],a[1])},f.precision=c||8;var h=Math.pow(10,f.precision);return f.clean=a||function(a){if(isNaN(a))throw new Error("NaN detected");if(!isFinite(a))throw new Error("Infinity detected");return Math.round(a)===a?a:Math.round(a*h)/h},f.inject=d,a||(f.fast=d(function(a){return a}),"undefined"!=typeof b&&"object"==typeof b.exports?b.exports=f:window.Vec2=window.Vec2||f),f}()},{}],15:[function(a,b,c){function d(a,b,c){c||(c={}),this.width=a,this.height=b,this.points=[],this.introLines=new f.Object3D,this.pins=[],this.markers=[],this.satelliteAnimations=[],this.satelliteMeshes=[],this.satellites={},this.quadtree=new g(new h(180,360),5),this.active=!0;var d={font:"Inconsolata",baseColor:"#ffcc00",markerColor:"#ffcc00",pinColor:"#00eeee",satelliteColor:"#ff0000",introLinesAltitude:1.1,introLinesDuration:2e3,introLinesColor:"#8FD8D8",introLinesCount:60,scale:1,dayLength:28e3,maxPins:500,maxMarkers:4,data:[],tiles:[],viewAngle:.1,cameraAngle:Math.PI};for(var e in d)this[e]||(this[e]=d[e],void 0!==c[e]&&(this[e]=c[e]));0===this.dayLength?this.rotationSpeed=0:this.rotationSpeed=1e3/this.dayLength,this.setScale(this.scale),this.renderer=new f.WebGLRenderer({antialias:!0}),this.renderer.setSize(this.width,this.height),this.renderer.gammaInput=!0,this.renderer.gammaOutput=!0,this.domElement=this.renderer.domElement,this.data.sort(function(a,b){return b.lng-2*b.label.length-(a.lng-2*a.label.length)});for(var e=0;e0&&this.firstRunTime+(next=this.data.pop()).when=Date.now()&&this.data.push(next)}},q=function(){this.hexGrid&&this.scene.remove(this.hexGrid);var a=["#define PI 3.141592653589793238462643","#define DISTANCE 500.0","#define INTRODURATION "+(parseFloat(this.introLinesDuration)+1e-5),"#define INTROALTITUDE "+(parseFloat(this.introLinesAltitude)+1e-5),"attribute float lng;","uniform float currentTime;","varying vec4 vColor;","","void main()","{"," vec3 newPos = position;"," float opacityVal = 0.0;"," float introStart = INTRODURATION * ((180.0 + lng)/360.0);"," if(currentTime > introStart){"," opacityVal = 1.0;"," }"," if(currentTime > introStart && currentTime < introStart + INTRODURATION / 8.0){"," newPos = position * INTROALTITUDE;"," opacityVal = .3;"," }"," if(currentTime > introStart + INTRODURATION / 8.0 && currentTime < introStart + INTRODURATION / 8.0 + 200.0){"," newPos = position * (1.0 + ((INTROALTITUDE-1.0) * (1.0-(currentTime - introStart-(INTRODURATION/8.0))/200.0)));"," }"," vColor = vec4( color, opacityVal );"," gl_Position = projectionMatrix * modelViewMatrix * vec4(newPos, 1.0);","}"].join("\n"),b=["varying vec4 vColor;","void main()","{"," gl_FragColor = vColor;"," float depth = gl_FragCoord.z / gl_FragCoord.w;"," float fogFactor = smoothstep("+parseInt(this.cameraDistance)+".0,"+parseInt(this.cameraDistance+300)+".0, depth );"," vec3 fogColor = vec3(0.0);"," gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w ), fogFactor );","}"].join("\n"),c={lng:{type:"f",value:null}};this.pointUniforms={currentTime:{type:"f",value:0}};var d=new f.ShaderMaterial({uniforms:this.pointUniforms,attributes:c,vertexShader:a,fragmentShader:b,transparent:!0,vertexColors:f.VertexColors,side:f.DoubleSide}),e=4*this.tiles.length,g=new f.BufferGeometry;g.addAttribute("index",Uint16Array,3*e,1),g.addAttribute("position",Float32Array,3*e,3),g.addAttribute("normal",Float32Array,3*e,3),g.addAttribute("color",Float32Array,3*e,3),g.addAttribute("lng",Float32Array,3*e,1);for(var h=g.attributes.lng.array,i=m(this.baseColor).hueSet(),j=[],k=0;k5&&q(s+3,r.b[0].x,r.b[0].y,r.b[0].z,r.b[5].x,r.b[5].y,r.b[5].z,r.b[4].x,r.b[4].y,r.b[4].z,r.lat,r.lon,v)}g.offsets=[];for(var w=e/l,k=0;w>k;k++){var x={start:k*l*3,index:k*l*3,count:3*Math.min(e-k*l,l)};g.offsets.push(x)}g.computeBoundingSphere(),this.hexGrid=new f.Mesh(g,d),this.scene.add(this.hexGrid)},r=function(){for(var a,b=new f.LineBasicMaterial({color:this.introLinesColor,transparent:!0,linewidth:2,opacity:.5}),c=0;ci;i++){var j=n.mapPoint(e,g-5*i);a=new f.Vector3(j.x*this.introLinesAltitude,j.y*this.introLinesAltitude,j.z*this.introLinesAltitude),d.vertices.push(a)}this.introLines.add(new f.Line(d,b))}this.scene.add(this.introLines)},s=function(a){var b,c=!1,d=0,e=Date.now(),g=!1,h=new f.Vector3(0,0,0),i=new f.Projector;a.domElement.onmousedown=function(a){c=!0,d=a.clientX,e=Date.now(),g=!1},a.domElement.onmouseup=function(b){c=!1,a.resetRotationSpeed()},a.domElement.onmouseleave=function(b){c=!1,a.resetRotationSpeed()};var j=function(f,i){h.x=2*(f.clientX/a.width)-1,h.y=1-2*(f.clientY/a.height);var k=Date.now()-e;c&&k&&(g=!0,a.setRotationSpeed((f.clientX-d)/a.width/(k/1e3)),e=Date.now(),d=f.clientX,clearTimeout(b),i||(b=setTimeout(function(){j(f,!0)},100)))},k=function(b){if(!g){for(var c=i.pickingRay(h.clone(),a.camera),d=c.intersectObjects(a.scene.children),e=1.1*a.cameraDistance,f=null,j=0;j0)){var k=a.camera.position.distanceTo(d[j].object.position);e>k&&(e=k,f=objName)}null!=f&&a.clickHandler&&a.clickHandler(f)}};a.domElement.onmousemove=j,a.domElement.onclick=k};d.prototype.init=function(a){this.camera=new f.PerspectiveCamera(50,this.width/this.height,1,this.cameraDistance+300),this.camera.position.z=this.cameraDistance,this.scene=new f.Scene,this.scene.fog=new f.Fog(0,this.cameraDistance,this.cameraDistance+300),r.call(this),this.smokeProvider=new l(this.scene),q.call(this),setTimeout(a,500)},d.prototype.destroy=function(a){var b=this;this.active=!1,setTimeout(function(){for(;b.scene.children.length>0;)b.scene.remove(b.scene.children[0]);"function"==typeof a&&a()},1e3)},d.prototype.addPin=function(a,b,c,d){a=parseFloat(a),b=parseFloat(b);var e={lineColor:this.pinColor,topColor:this.pinColor,font:this.font,id:d},f=1.2;"string"==typeof c&&0!==c.length||(f-=.05+.05*Math.random());var g=new i(a,b,c,f,this.scene,this.smokeProvider,e);this.pins.push(g);var j=o(a,b);if(g.pos_=new h(parseInt(j.x),parseInt(j.y)),c.length>0?g.rad_=j.rad:g.rad_=1,this.quadtree.addObject(g),c.length>0){var k=this.quadtree.getCollisionsForObject(g),l=0,m=0,n=[];for(var p in k)k[p].text.length>0&&(l++,k[p].age()>5e3?n.push(k[p]):m++);if(l>0&&0==m)for(var p=0;p0&&(g.hideLabel(),g.hideSmoke(),g.hideTop(),g.changeAltitude(.05*Math.random()+1.1))}if(this.pins.length>this.maxPins){var q=this.pins.shift();this.quadtree.removeObject(q),q.remove()}return g},d.prototype.addMarker=function(a,b,c,d){var e,f={markerColor:this.markerColor,lineColor:this.markerColor,font:this.font};return e="boolean"==typeof d&&d?new j(a,b,c,1.2,this.markers[this.markers.length-1],this.scene,f):"object"==typeof d?new j(a,b,c,1.2,d,this.scene,f):new j(a,b,c,1.2,null,this.scene,f),this.markers.push(e),this.markers.length>this.maxMarkers&&this.markers.shift().remove(),e},d.prototype.addSatellite=function(a,b,c,d,e,f){d||(d={}),void 0==d.coreColor&&(d.coreColor=this.satelliteColor);var g=new k(a,b,c,this.scene,d,e,f);return this.satellites[g.toString()]||(this.satellites[g.toString()]=g),g.onRemove(function(){delete this.satellites[g.toString()]}.bind(this)),g},d.prototype.addConstellation=function(a,b){for(var c,d=[],e=0;ethis.maxPins;){var b=this.pins.shift();this.quadtree.removeObject(b),b.remove()}},d.prototype.setMaxMarkers=function(a){for(this.maxMarkers=a;this.markers.length>this.maxMarkers;)this.markers.shift().remove()},d.prototype.setBaseColor=function(a){this.baseColor=a,q.call(this)},d.prototype.setMarkerColor=function(a){this.markerColor=a,this.scene._encom_markerTexture=null},d.prototype.setPinColor=function(a){this.pinColor=a},d.prototype.setScale=function(a){this.scale=a,this.cameraDistance=1700/a,this.scene&&this.scene.fog&&(this.scene.fog.near=this.cameraDistance,this.scene.fog.far=this.cameraDistance+300,q.call(this),this.camera.far=this.cameraDistance+300,this.camera.updateProjectionMatrix())},d.prototype.setRotationSpeed=function(a){this.rotationSpeed=a},d.prototype.resetRotationSpeed=function(){this.rotationSpeed=this.defaultRotationSpeed},d.prototype.tick=function(){if(this.camera){this.firstRunTime||(this.firstRunTime=Date.now()),p.call(this),e.update(),this.lastRenderDate||(this.lastRenderDate=new Date),this.firstRenderDate||(this.firstRenderDate=new Date),this.totalRunTime=new Date-this.firstRenderDate;var a=new Date-this.lastRenderDate;this.lastRenderDate=new Date;var b=this.rotationSpeed*a/1e3*2*Math.PI;this.cameraAngle+=b,this.active||(this.cameraDistance+=1e3*a/1e3),this.camera.position.x=this.cameraDistance*Math.cos(this.cameraAngle)*Math.cos(this.viewAngle),this.camera.position.y=Math.sin(this.viewAngle)*this.cameraDistance,this.camera.position.z=this.cameraDistance*Math.sin(this.cameraAngle)*Math.cos(this.viewAngle);for(var c in this.satellites)this.satellites[c].tick(this.camera.position,this.cameraAngle,a);for(var c=0;cthis.totalRunTime?(this.totalRunTime/this.introLinesDuration<.1&&(this.introLines.children[0].material.opacity=this.totalRunTime/this.introLinesDuration*10-.2),this.totalRunTime/this.introLinesDuration>.8?this.introLines.children[0].material.opacity=5*Math.max(1-this.totalRunTime/this.introLinesDuration,0):this.introLines.children[0].material.opacity=1,this.introLines.rotateY(2*Math.PI/(this.introLinesDuration/a))):this.introLines&&(this.scene.remove(this.introLines),delete[this.introLines]),this.pointUniforms.currentTime.value=this.totalRunTime,this.smokeProvider.tick(this.totalRunTime),this.camera.lookAt(this.scene.position),this.renderer.render(this.scene,this.camera)}},d.prototype.setClickHandler=function(a){this.clickHandler=a},b.exports=d},{"./Marker":16,"./Pin":17,"./Satellite":18,"./SmokeProvider":19,"./utils":21,"hexasphere.js":3,"pusher.color":6,quadtree2:8,three:12,"tween.js":13,vec2:14}],16:[function(a,b,c){var d=a("three"),e=a("tween.js"),f=a("./utils"),g=function(a){var b,c,e=30,g=30;return b=f.renderToCanvas(e,g,function(b){b.fillStyle=a,b.strokeStyle=a,b.lineWidth=3,b.beginPath(),b.arc(e/2,g/2,e/3,0,2*Math.PI),b.stroke(),b.beginPath(),b.arc(e/2,g/2,e/5,0,2*Math.PI),b.fill()}),c=new d.Texture(b),c.needsUpdate=!0,c},h=function(a,b,c,h,i,j,k){var l,m,n,o,p,q,r={lineColor:"#FFCC00",lineWidth:1,markerColor:"#FFCC00",labelColor:"#FFF",font:"Inconsolata",fontSize:20,drawTime:2e3,lineSegments:150};if(this.lat=parseFloat(a),this.lon=parseFloat(b),this.text=c,this.altitude=parseFloat(h),this.scene=j,this.previous=i,this.next=[],this.previous&&this.previous.next.push(this),k)for(var s in r)void 0!=k[s]&&(r[s]=k[s]);this.opts=r,l=f.mapPoint(a,b),i&&(m=f.mapPoint(i.lat,i.lon)),j._encom_markerTexture||(j._encom_markerTexture=g(this.opts.markerColor)),n=new d.SpriteMaterial({map:j._encom_markerTexture,opacity:.7,depthTest:!0,fog:!0}),this.marker=new d.Sprite(n),this.marker.scale.set(0,0),this.marker.position.set(l.x*h,l.y*h,l.z*h),o=f.createLabel(c.toUpperCase(),this.opts.fontSize,this.opts.labelColor,this.opts.font,this.opts.markerColor),p=new d.Texture(o),p.needsUpdate=!0,q=new d.SpriteMaterial({map:p,useScreenCoordinates:!1,opacity:0,depthTest:!0,fog:!0}),this.labelSprite=new d.Sprite(q),this.labelSprite.position={x:l.x*h*1.1,y:l.y*h*1.05+(l.y<0?-15:30),z:l.z*h*1.1},this.labelSprite.scale.set(o.width,o.height),new e.Tween({opacity:0}).to({opacity:1},500).onUpdate(function(){q.opacity=this.opacity}).start();var t=this;if(new e.Tween({x:0,y:0}).to({x:50,y:50},2e3).easing(e.Easing.Elastic.Out).onUpdate(function(){t.marker.scale.set(this.x,this.y)}).delay(this.previous?t.opts.drawTime:0).start(),this.previous){var u,v,w,x,y,z,A,B,C,D,E,F,G=[],H=[];t.geometrySpline=new d.Geometry,u=new d.LineBasicMaterial({color:this.opts.lineColor,transparent:!0,linewidth:3,opacity:.5}),t.geometrySplineDotted=new d.Geometry,v=new d.LineBasicMaterial({color:this.opts.lineColor,linewidth:1,transparent:!0,opacity:.5}),w=(a-i.lat)/t.opts.lineSegments,x=(b-i.lon)/t.opts.lineSegments,y=f.mapPoint(i.lat,i.lon),G=[],H=[];for(var I=0;I=a.index&&(E.set(1.2*D.x,1.2*D.y,1.2*D.z),currentVert2.set(1.19*currentPoint2.x,1.19*currentPoint2.y,1.19*currentPoint2.z)),t.geometrySpline.verticesNeedUpdate=!0,t.geometrySplineDotted.verticesNeedUpdate=!0;G.length>0&&setTimeout(F,t.opts.drawTime/t.opts.lineSegments)},F(),this.scene.add(new d.Line(t.geometrySpline,u)),this.scene.add(new d.Line(t.geometrySplineDotted,v,d.LinePieces))}this.scene.add(this.marker),this.scene.add(this.labelSprite)};h.prototype.remove=function(){for(var a=0,b=this,c=function(d){for(var e=0;a>e;e++)d.geometrySpline.vertices[e].set(d.geometrySpline.vertices[e+1]),d.geometrySplineDotted.vertices[e].set(d.geometrySplineDotted.vertices[e+1]),d.geometrySpline.verticesNeedUpdate=!0,d.geometrySplineDotted.verticesNeedUpdate=!0;a++,a0,showTop:c.length>0,showSmoke:c.length>0,id:null};if(this.lat=a,this.lon=b,this.text=c,this.altitude=h,this.scene=i,this.smokeProvider=j,this.dateCreated=Date.now(),k)for(var t in s)void 0!=k[t]&&(s[t]=k[t]);this.opts=s,this.topVisible=s.showTop,this.smokeVisible=s.showSmoke,this.labelVisible=s.showLabel,this.lineGeometry=new d.Geometry,l=new d.LineBasicMaterial({color:s.lineColor,linewidth:s.lineWidth}),r=f.mapPoint(a,b),this.lineGeometry.vertices.push(new d.Vector3(r.x,r.y,r.z)),this.lineGeometry.vertices.push(new d.Vector3(r.x,r.y,r.z)),this.line=new d.Line(this.lineGeometry,l),m=f.createLabel(c,18,s.labelColor,s.font),n=new d.Texture(m),n.needsUpdate=!0,o=new d.SpriteMaterial({map:n,useScreenCoordinates:!1,opacity:0,depthTest:!0,fog:!0}),this.labelSprite=new d.Sprite(o),this.labelSprite.position={x:r.x*h*1.1,y:r.y*h+(r.y<0?-15:30),z:r.z*h*1.1},this.labelSprite.scale.set(m.width,m.height),p=new d.Texture(g(s.topColor)),p.needsUpdate=!0,q=new d.SpriteMaterial({map:p,depthTest:!0,fog:!0,opacity:0}),this.topSprite=new d.Sprite(q),this.topSprite.scale.set(20,20),this.topSprite.position.set(r.x*h,r.y*h,r.z*h),this.smokeVisible&&(this.smokeId=j.setFire(a,b,h));var u=this;(s.showTop||s.showLabel)&&new e.Tween({opacity:0}).to({opacity:1},500).onUpdate(function(){u.topVisible?q.opacity=this.opacity:q.opacity=0,u.labelVisible?o.opacity=this.opacity:o.opacity=0}).delay(1e3).start(),new e.Tween(r).to({x:r.x*h,y:r.y*h,z:r.z*h},1500).easing(e.Easing.Elastic.Out).onUpdate(function(){u.lineGeometry.vertices[1].x=this.x,u.lineGeometry.vertices[1].y=this.y,u.lineGeometry.vertices[1].z=this.z,u.lineGeometry.verticesNeedUpdate=!0}).start(),null!==this.opts.id&&void 0!==this.opts.id&&(this.labelSprite.name=this.opts.id,this.line.name=this.opts.id,this.topSprite.name=this.opts.id),this.scene.add(this.labelSprite),this.scene.add(this.line),this.scene.add(this.topSprite)};h.prototype.toString=function(){return""+this.lat+"_"+this.lon},h.prototype.changeAltitude=function(a){var b=f.mapPoint(this.lat,this.lon),c=this;new e.Tween({altitude:this.altitude}).to({altitude:a},1500).easing(e.Easing.Elastic.Out).onUpdate(function(){c.smokeVisible&&c.smokeProvider.changeAltitude(this.altitude,c.smokeId),c.topVisible&&c.topSprite.position.set(b.x*this.altitude,b.y*this.altitude,b.z*this.altitude),c.labelVisible&&(c.labelSprite.position={x:b.x*this.altitude*1.1,y:b.y*this.altitude+(b.y<0?-15:30),z:b.z*this.altitude*1.1}),c.lineGeometry.vertices[1].x=b.x*this.altitude,c.lineGeometry.vertices[1].y=b.y*this.altitude,c.lineGeometry.vertices[1].z=b.z*this.altitude,c.lineGeometry.verticesNeedUpdate=!0}).onComplete(function(){c.altitude=a}).start()},h.prototype.hideTop=function(){this.topVisible&&(this.topSprite.material.opacity=0,this.topVisible=!1)},h.prototype.showTop=function(){this.topVisible||(this.topSprite.material.opacity=1,this.topVisible=!0)},h.prototype.hideLabel=function(){this.labelVisible&&(this.labelSprite.material.opacity=0,this.labelVisible=!1)},h.prototype.showLabel=function(){this.labelVisible||(this.labelSprite.material.opacity=1,this.labelVisible=!0)},h.prototype.hideSmoke=function(){this.smokeVisible&&(this.smokeProvider.extinguish(this.smokeId),this.smokeVisible=!1)},h.prototype.showSmoke=function(){this.smokeVisible||(this.smokeId=this.smokeProvider.setFire(this.lat,this.lon,this.altitude),this.smokeVisible=!0)},h.prototype.age=function(){return Date.now()-this.dateCreated},h.prototype.remove=function(){this.scene.remove(this.labelSprite),this.scene.remove(this.line),this.scene.remove(this.topSprite),this.smokeVisible&&this.smokeProvider.extinguish(this.smokeId)},b.exports=h},{"./utils":21,three:12,"tween.js":13}],18:[function(a,b,c){var d=a("./TextureAnimator"),e=a("three"),f=a("./utils"),g=function(a,b,c,d,e,g,h,i){var j=a/c,k=Math.floor((a-d)/e),l=b-25,m=l/(a-d),n=0,o=0,p=0,q=f.hexToRgb(g);return f.renderToCanvas(a*b/c,b*c,function(c){for(var f=0;a>f;f++){f-p*j>=j&&(n=0,o+=b,p++);var g=n+25,l=o+Math.floor(b/2);c.lineWidth=2,c.strokeStyle=i;var r=Math.PI/16,s=-Math.PI+Math.PI/4,t=8,u=Math.floor(a-2*(a-d)/e)+1;d>f&&(t=t*f/d);for(var v=Math.floor((u-d)/2)+d,w=0;4>w;w++){if(c.beginPath(),d>f||f>=a)c.arc(g,l,t,w*Math.PI/2+s+r,w*Math.PI/2+s+Math.PI/2-2*r);else if(f>d&&v>f){var x=v-d,y=3*Math.PI/2,z=f-d,A=y/x,B=-Math.PI+Math.PI/4+r+A*z;c.arc(g,l,t,Math.max(w*Math.PI/2+s,B),Math.max(w*Math.PI/2+s+Math.PI/2-2*r,B+Math.PI/2-2*r))}else if(f>=v&&u>f){var x=u-v,y=2*w*Math.PI/4,z=f-v,A=y/x,B=Math.PI/2+Math.PI/4+r+A*z;c.arc(g,l,t,B,B+Math.PI/2-2*r)}else if(f>=u&&(a-u)/2+u>f){var x=(a-u)/2,y=Math.PI/2,z=f-u,A=y/x,B=w*(Math.PI/2)+Math.PI/4+r+A*z;c.arc(g,l,t,B,B+Math.PI/2-2*r)}else c.arc(g,l,t,w*Math.PI/2+s+r,w*Math.PI/2+s+Math.PI/2-2*r);c.stroke()}for(var C,D=0;e>D;D++)C=f-k*D-d,C>0&&b-25>C*m&&(c.strokeStyle="rgba("+q.r+","+q.g+","+q.b+","+(.9-C*m/(b-25))+")",c.lineWidth=2,c.beginPath(),c.arc(g,l,C*m,-Math.PI/12,Math.PI/12),c.stroke());c.fillStyle="#000",c.beginPath(),c.arc(g,l,3,0,2*Math.PI),c.fill(),c.strokeStyle=h,c.lineWidth=2,c.beginPath(),d>f?c.arc(g,l,3*f/d,0,2*Math.PI):c.arc(g,l,3,0,2*Math.PI),c.stroke(),n+=b}})},h=function(a,b,c,h,i,j,k){var l,m,n,o,p,q,r,s=f.mapPoint(a,b);s.x*=c,s.y*=c,s.z*=c;var m={numWaves:8,waveColor:"#FFF",coreColor:"#FF0000",shieldColor:"#FFF",size:1};if(this.lat=a,this.lon=b,this.altitude=c,this.scene=h,this.onRemoveList=[],n=50,o=100,p=10,q=Math.floor(n/8),i)for(var t in m)void 0!=i[t]&&(m[t]=i[t]);this.opts=m,j?(this.canvas=j,k?this.texture=k:(this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,r=Math.floor(n-2*(n-q)/m.numWaves)+1,this.animator=new d(this.texture,p,n/p,n,80,r))):(this.canvas=g(n,o,p,q,m.numWaves,m.waveColor,m.coreColor,m.shieldColor),this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,r=Math.floor(n-2*(n-q)/m.numWaves)+1,this.animator=new d(this.texture,p,n/p,n,80,r)),l=new e.PlaneGeometry(150*m.size,150*m.size,1,1),this.material=new e.MeshBasicMaterial({map:this.texture,depthTest:!1,transparent:!0}),this.mesh=new e.Mesh(l,this.material),this.mesh.tiltMultiplier=Math.PI/2*(1-Math.abs(a/90)),this.mesh.tiltDirection=a>0?-1:1,this.mesh.lon=b,this.mesh.position.set(s.x,s.y,s.z),this.mesh.rotation.z=-1*(a/90)*Math.PI/2,this.mesh.rotation.y=b/180*Math.PI,h.add(this.mesh)};h.prototype.changeAltitude=function(a){var b=f.mapPoint(this.lat,this.lon);b.x*=a,b.y*=a,b.z*=a,this.altitude=a,this.mesh.position.set(b.x,b.y,b.z)},h.prototype.changeCanvas=function(a,b,c,f){numFrames=50,pixels=100,rows=10,waveStart=Math.floor(numFrames/8),a?this.opts.numWaves=a:a=this.opts.numWaves,b?this.opts.waveColor=b:b=this.opts.waveColor,c?this.opts.coreColor=c:c=this.opts.coreColor,f?this.opts.shieldColor=f:f=this.opts.shieldColor,this.canvas=g(numFrames,pixels,rows,waveStart,a,b,c,f),this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,repeatAt=Math.floor(numFrames-2*(numFrames-waveStart)/a)+1,this.animator=new d(this.texture,rows,numFrames/rows,numFrames,80,repeatAt),this.material.map=this.texture},h.prototype.tick=function(a,b,c){this.mesh.lookAt(a),this.mesh.rotateZ(this.mesh.tiltDirection*Math.PI/2),this.mesh.rotateZ(Math.sin(b+this.mesh.lon/180*Math.PI)*this.mesh.tiltMultiplier*this.mesh.tiltDirection*-1),this.animator&&this.animator.update(c)},h.prototype.remove=function(){this.scene.remove(this.mesh);for(var a=0;a 0.0 && active > 0.0) {"," dt = mod(dt,1500.0);"," }"," float opacity = 1.0 - dt/ 1500.0;"," if (dt == 0.0 || active == 0.0){"," opacity = 0.0;"," }"," vec3 newPos = getPos(myStartLat, myStartLon - ( dt / 50.0));"," vColor = vec4( color, opacity );"," vec4 mvPosition = modelViewMatrix * vec4( newPos, 1.0 );"," gl_PointSize = 2.5 - (dt / 1500.0);"," gl_Position = projectionMatrix * mvPosition;","}"].join("\n"),g=["varying vec4 vColor;","void main()","{"," gl_FragColor = vColor;"," float depth = gl_FragCoord.z / gl_FragCoord.w;"," float fogFactor = smoothstep(1500.0, 1800.0, depth );"," vec3 fogColor = vec3(0.0);"," gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w), fogFactor );","}"].join("\n"),h=function(a,b){var c={smokeCount:5e3,smokePerPin:30,smokePerSecond:20};if(b)for(var e in c)void 0!==b[e]&&(c[e]=b[e]);this.opts=c,this.geometry=new d.Geometry,this.attributes={myStartTime:{type:"f",value:[]},myStartLat:{type:"f",value:[]},myStartLon:{type:"f",value:[]},altitude:{type:"f",value:[]},active:{type:"f",value:[]}},this.uniforms={currentTime:{type:"f",value:0},color:{type:"c",value:new d.Color("#aaa")}};for(var h=new d.ShaderMaterial({uniforms:this.uniforms,attributes:this.attributes,vertexShader:f,fragmentShader:g,transparent:!0}),e=0;ethis.tileDisplayDuration;)if(this.shutDownFlag&&this.currentTile>=e)this.done=!0,this.shutDownCb();else{this.currentDisplayTime-=this.tileDisplayDuration,this.currentTile++,this.currentTile!=e||this.shutDownFlag||(this.currentTile=g);var c=this.currentTile%this.tilesHorizontal;a.offset.x=c/this.tilesHorizontal;var d=Math.floor(this.currentTile/this.tilesHorizontal);a.offset.y=1-d/this.tilesVertical-1/this.tilesVertical}},this.shutDown=function(a){_this.shutDownFlag=!0,_this.shutDownCb=a}};b.exports=e},{three:12}],21:[function(a,b,c){var d={renderToCanvas:function(a,b,c){var d=document.createElement("canvas");return d.width=a,d.height=b,c(d.getContext("2d")),d},mapPoint:function(a,b,c){c||(c=500);var d=(90-a)*Math.PI/180,e=(180-b)*Math.PI/180,f=c*Math.sin(d)*Math.cos(e),g=c*Math.cos(d),h=c*Math.sin(d)*Math.sin(e); return{x:f,y:g,z:h}},hexToRgb:function(a){var b=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;a=a.replace(b,function(a,b,c,d){return b+b+c+c+d+d});var c=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a);return c?{r:parseInt(c[1],16),g:parseInt(c[2],16),b:parseInt(c[3],16)}:null},createLabel:function(a,b,c,d,e){var f=document.createElement("canvas"),g=f.getContext("2d");g.font=b+"pt "+d;var h=g.measureText(a).width;return f.width=h,f.height=b+10,f.width%2&&f.width++,f.height%2&&f.height++,e&&(f.height+=30),g.font=b+"pt "+d,g.textAlign="center",g.textBaseline="middle",g.strokeStyle="black",g.miterLimit=2,g.lineJoin="circle",g.lineWidth=6,g.strokeText(a,f.width/2,f.height/2),g.lineWidth=2,g.fillStyle=c,g.fillText(a,f.width/2,f.height/2),e&&(g.strokeStyle=e,g.lineWidth=4,g.beginPath(),g.moveTo(0,f.height-10),g.lineTo(f.width-1,f.height-10),g.stroke()),f}};b.exports=d},{}]},{},[1]); \ No newline at end of file diff --git a/src/Globe.js b/src/Globe.js index 06c9bf0..acf86d5 100644 --- a/src/Globe.js +++ b/src/Globe.js @@ -20,7 +20,7 @@ var latLonToXYZ = function(width, height, lat,lon){ var latLon2d = function(lat,lon){ - var rad = 2 + (Math.abs(lat)/90) * 15; + var rad = 2 + (Math.abs(lat)/90) * 5; return {x: lat+90, y:lon + 180, rad: rad}; }; From 93e4e64cb0f7367852ab28e124a23627e17ccb15 Mon Sep 17 00:00:00 2001 From: Rob Scanlon Date: Mon, 29 Feb 2016 19:57:42 -0500 Subject: [PATCH 4/5] click handler improvement and vertical rotation --- build/encom-globe.js | 59 ++++++++++++++++++++++++++++++++-------- build/encom-globe.min.js | 4 +-- display/display.js | 3 +- src/Globe.js | 59 ++++++++++++++++++++++++++++++++-------- 4 files changed, 98 insertions(+), 27 deletions(-) diff --git a/build/encom-globe.js b/build/encom-globe.js index c112c59..3e28b27 100644 --- a/build/encom-globe.js +++ b/build/encom-globe.js @@ -44164,7 +44164,6 @@ var addInitialData = function(){ } }; - var createParticles = function(){ if(this.hexGrid){ @@ -44385,17 +44384,36 @@ var createIntroLines = function(){ var createMouseBehaviors = function(globe){ var mouseDown = false, - mousePos = 0, + mousePos = {x: 0, y: 0}, lastTime = Date.now(), - movedSinceMouseDown = false, + distanceSinceMouseDown = 0, mouseTimeout, + verticalTimeout, mouseVector = new THREE.Vector3(0,0,0), projector = new THREE.Projector(); - - globe.domElement.onmousedown = function(e){ mouseDown = true; mousePos = e.clientX; lastTime = Date.now(); movedSinceMouseDown=false;}; - globe.domElement.onmouseup = function(e){ mouseDown = false; globe.resetRotationSpeed()}; - globe.domElement.onmouseleave = function(e){ mouseDown = false; globe.resetRotationSpeed();}; + var onmouseup = function(){ + mouseDown = false; + globe.resetRotationSpeed(); + clearTimeout(verticalTimeout); + verticalTimeout = setTimeout(function(){ + new TWEEN.Tween( {viewAngle: globe.viewAngle}) + .easing( TWEEN.Easing.Quadratic.InOut) + .to( {viewAngle: globe.defaultViewAngle}, 1000 ) + .onUpdate(function(){ + globe.viewAngle = this.viewAngle; + }).start(); + + },globe.viewAngleResetTime); + }; + + var onmousedown = function(e){ + clearTimeout(verticalTimeout); + mouseDown = true; + mousePos = {x: e.clientX, y: e.clientY}; + lastTime = Date.now(); + movedSinceMouseDown=0; + }; var onmousemove = function(e, secondCall){ @@ -44404,12 +44422,13 @@ var createMouseBehaviors = function(globe){ var diff = Date.now() - lastTime; if(mouseDown && diff){ - movedSinceMouseDown = true; + movedSinceMouseDown += Math.abs(e.clientX-mousePos.x) + Math.abs(e.clientY-mousePos.y); - globe.setRotationSpeed(((e.clientX-mousePos)/globe.width) / (diff/1000)); + globe.setRotationSpeed(((e.clientX-mousePos.x)/globe.width) / (diff/1000)); + globe.setVerticalRotationSpeed(((e.clientY-mousePos.y)/globe.height / 2) / (diff/1000)); lastTime = Date.now(); - mousePos = e.clientX; + mousePos = {x: e.clientX, y: e.clientY}; clearTimeout(mouseTimeout); if(!secondCall){ mouseTimeout = setTimeout(function(){onmousemove(e, true)},100); @@ -44418,7 +44437,7 @@ var createMouseBehaviors = function(globe){ }; var onclick = function (e) { - if(!movedSinceMouseDown){ + if(movedSinceMouseDown < 50){ var raycaster = projector.pickingRay( mouseVector.clone(), globe.camera ); var intersects = raycaster.intersectObjects(globe.scene.children); var minDistance = globe.cameraDistance * 1.1; @@ -44442,6 +44461,9 @@ var createMouseBehaviors = function(globe){ } } + globe.domElement.onmousedown = onmousedown; + globe.domElement.onmouseup = onmouseup; + globe.domElement.onmouseleave = onmouseup; globe.domElement.onmousemove = onmousemove; globe.domElement.onclick = onclick; @@ -44487,7 +44509,8 @@ function Globe(width, height, opts){ data: [], tiles: [], viewAngle: .1, - cameraAngle: Math.PI + cameraAngle: Math.PI, + viewAngleResetTime: 30000 }; for(var i in defaults){ @@ -44505,6 +44528,8 @@ function Globe(width, height, opts){ this.rotationSpeed = 1000 * 1/this.dayLength; } + this.verticalRotationSpeed = 0; + this.setScale(this.scale); this.renderer = new THREE.WebGLRenderer( { antialias: true } ); @@ -44522,6 +44547,7 @@ function Globe(width, height, opts){ } this.defaultRotationSpeed = this.rotationSpeed; + this.defaultViewAngle = this.viewAngle; createMouseBehaviors(this); @@ -44770,8 +44796,13 @@ Globe.prototype.setRotationSpeed = function(rotationSpeed){ this.rotationSpeed = rotationSpeed; } +Globe.prototype.setVerticalRotationSpeed = function(rotationSpeed){ + this.verticalRotationSpeed = rotationSpeed; +} + Globe.prototype.resetRotationSpeed = function(){ this.rotationSpeed = this.defaultRotationSpeed; + this.verticalRotationSpeed = 0; } Globe.prototype.tick = function(){ @@ -44799,8 +44830,12 @@ Globe.prototype.tick = function(){ var renderTime = new Date() - this.lastRenderDate; this.lastRenderDate = new Date(); var rotateCameraBy = this.rotationSpeed * renderTime/1000 * 2 * Math.PI; + var rotateVerticalCameraBy = this.verticalRotationSpeed * renderTime/1000 * 2 * Math.PI; this.cameraAngle += rotateCameraBy; + this.viewAngle += rotateVerticalCameraBy; + this.viewAngle = Math.min(Math.PI/2, this.viewAngle); + this.viewAngle = Math.max(-Math.PI/2, this.viewAngle); if(!this.active){ this.cameraDistance += (1000 * renderTime/1000); diff --git a/build/encom-globe.min.js b/build/encom-globe.min.js index 37ddaa7..72fe8e8 100644 --- a/build/encom-globe.min.js +++ b/build/encom-globe.min.js @@ -14,5 +14,5 @@ m[n]>=0&&a.numSupportedMorphTargets++}if(a.morphNormals){a.numSupportedMorphNorm m.curves=l.curves,n.push(m),n;var o=!e.Shape.Utils.isClockWise(i[0].getPoints());o=a?!o:o;var p,q=[],r=[],s=[],t=0;for(r[t]=void 0,s[t]=[],c=0,d=i.length;d>c;c++)l=i[c],p=l.getPoints(),k=e.Shape.Utils.isClockWise(p),k=a?!k:k,k?(!o&&r[t]&&t++,r[t]={s:new e.Shape,p:p},r[t].s.actions=l.actions,r[t].s.curves=l.curves,o&&t++,s[t]=[]):s[t].push({h:l,p:p[0]});if(r.length>1){for(var u=!1,v=[],w=0,x=r.length;x>w;w++)q[w]=[];for(var w=0,x=r.length;x>w;w++)for(var y=(r[w],s[w]),z=0;z0&&(u||(s=q))}var D,E,F;for(c=0,d=r.length;d>c;c++)for(m=r[c].s,n.push(m),D=s[c],E=0,F=D.length;F>E;E++)m.holes.push(D[E].h);return n},e.Shape=function(){e.Path.apply(this,arguments),this.holes=[]},e.Shape.prototype=Object.create(e.Path.prototype),e.Shape.prototype.extrude=function(a){var b=new e.ExtrudeGeometry(this,a);return b},e.Shape.prototype.makeGeometry=function(a){var b=new e.ShapeGeometry(this,a);return b},e.Shape.prototype.getPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;c>b;b++)d[b]=this.holes[b].getTransformedPoints(a,this.bends);return d},e.Shape.prototype.getSpacedPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;c>b;b++)d[b]=this.holes[b].getTransformedSpacedPoints(a,this.bends);return d},e.Shape.prototype.extractAllPoints=function(a){return{shape:this.getTransformedPoints(a),holes:this.getPointsHoles(a)}},e.Shape.prototype.extractPoints=function(a){return this.useSpacedPoints?this.extractAllSpacedPoints(a):this.extractAllPoints(a)},e.Shape.prototype.extractAllSpacedPoints=function(a){return{shape:this.getTransformedSpacedPoints(a),holes:this.getSpacedPointsHoles(a)}},e.Shape.Utils={triangulateShape:function(a,b){function c(a,b,c){return a.x!=b.x?a.xg){var p;if(n>0){if(0>o||o>n)return[];if(p=k*l-j*m,0>p||p>n)return[]}else{if(o>0||n>o)return[];if(p=k*l-j*m,p>0||n>p)return[]}if(0==p)return!f||0!=o&&o!=n?[a]:[];if(p==n)return!f||0!=o&&o!=n?[b]:[];if(0==o)return[d];if(o==n)return[e];var q=p/n;return[{x:a.x+q*h,y:a.y+q*i}]}if(0!=o||k*l!=j*m)return[];var r=0==h&&0==i,s=0==j&&0==k;if(r&&s)return a.x!=d.x||a.y!=d.y?[]:[a];if(r)return c(d,e,a)?[a]:[];if(s)return c(a,b,d)?[d]:[];var t,u,v,w,x,y,z,A;return 0!=h?(a.x=v?z>w?[]:w==z?f?[]:[x]:A>=w?[x,u]:[x,y]:v>A?[]:v==A?f?[]:[t]:A>=w?[t,u]:[t,y]}function f(a,b,c,d){var e=1e-10,f=b.x-a.x,g=b.y-a.y,h=c.x-a.x,i=c.y-a.y,j=d.x-a.x,k=d.y-a.y,l=f*i-g*h,m=f*k-g*j;if(Math.abs(l)>e){var n=j*i-k*h;return l>0?m>=0&&n>=0:m>=0||n>=0}return m>0}function g(a,b){function c(a,b){var c=s.length-1,d=a-1;0>d&&(d=c);var e=a+1;e>c&&(e=0);var g=f(s[a],s[d],s[e],h[b]);if(!g)return!1;var i=h.length-1,j=b-1;0>j&&(j=i);var k=b+1;return k>i&&(k=0),g=f(h[b],h[j],h[k],s[a]),!!g}function e(a,b){var c,e,f;for(c=0;c0)return!0;return!1}function g(a,c){var e,f,g,h,i;for(e=0;e0)return!0;return!1}for(var h,i,j,k,l,m,n,o,p,q,r,s=a.concat(),t=[],u=[],v=0,w=b.length;w>v;v++)t.push(v);for(var x=2*t.length;t.length>0;){if(x--,0>x){console.log("Infinite Loop! Holes left:"+t.length+", Probably Hole outside Shape!");break}for(j=0;j=0)break;u[n]=!0}if(i>=0)break}}return s}for(var h,i,j,k,l,m,n={},o=a.concat(),p=0,q=b.length;q>p;p++)Array.prototype.push.apply(o,b[p]);for(h=0,i=o.length;i>h;h++)l=o[h].x+":"+o[h].y,void 0!==n[l]&&console.log("Duplicate point",l),n[l]=h;var r=g(a,b),s=e.FontUtils.Triangulate(r,!1);for(h=0,i=s.length;i>h;h++)for(k=s[h],j=0;3>j;j++)l=k[j].x+":"+k[j].y,m=n[l],void 0!==m&&(k[j]=m);return s.concat()},isClockWise:function(a){return e.FontUtils.Triangulate.area(a)<0},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){var c=1-a;return 3*c*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a,b)+this.b3p1(a,c)+this.b3p2(a,d)+this.b3p3(a,e)}},e.LineCurve=function(a,b){this.v1=a,this.v2=b},e.LineCurve.prototype=Object.create(e.Curve.prototype),e.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);return b.multiplyScalar(a).add(this.v1),b},e.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)},e.LineCurve.prototype.getTangent=function(a){var b=this.v2.clone().sub(this.v1);return b.normalize()},e.QuadraticBezierCurve=function(a,b,c){this.v0=a,this.v1=b,this.v2=c},e.QuadraticBezierCurve.prototype=Object.create(e.Curve.prototype),e.QuadraticBezierCurve.prototype.getPoint=function(a){var b,c;return b=e.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x),c=e.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y),new e.Vector2(b,c)},e.QuadraticBezierCurve.prototype.getTangent=function(a){var b,c;b=e.Curve.Utils.tangentQuadraticBezier(a,this.v0.x,this.v1.x,this.v2.x),c=e.Curve.Utils.tangentQuadraticBezier(a,this.v0.y,this.v1.y,this.v2.y);var d=new e.Vector2(b,c);return d.normalize(),d},e.CubicBezierCurve=function(a,b,c,d){this.v0=a,this.v1=b,this.v2=c,this.v3=d},e.CubicBezierCurve.prototype=Object.create(e.Curve.prototype),e.CubicBezierCurve.prototype.getPoint=function(a){var b,c;return b=e.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),c=e.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y),new e.Vector2(b,c)},e.CubicBezierCurve.prototype.getTangent=function(a){var b,c;b=e.Curve.Utils.tangentCubicBezier(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),c=e.Curve.Utils.tangentCubicBezier(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);var d=new e.Vector2(b,c);return d.normalize(),d},e.SplineCurve=function(a){this.points=void 0==a?[]:a},e.SplineCurve.prototype=Object.create(e.Curve.prototype),e.SplineCurve.prototype.getPoint=function(a){var b,c,d,f=new e.Vector2,g=[],h=this.points;return b=(h.length-1)*a,c=Math.floor(b),d=b-c,g[0]=0==c?c:c-1,g[1]=c,g[2]=c>h.length-2?h.length-1:c+1,g[3]=c>h.length-3?h.length-1:c+2,f.x=e.Curve.Utils.interpolate(h[g[0]].x,h[g[1]].x,h[g[2]].x,h[g[3]].x,d),f.y=e.Curve.Utils.interpolate(h[g[0]].y,h[g[1]].y,h[g[2]].y,h[g[3]].y,d),f},e.EllipseCurve=function(a,b,c,d,e,f,g){this.aX=a,this.aY=b,this.xRadius=c,this.yRadius=d,this.aStartAngle=e,this.aEndAngle=f,this.aClockwise=g},e.EllipseCurve.prototype=Object.create(e.Curve.prototype),e.EllipseCurve.prototype.getPoint=function(a){var b,c=this.aEndAngle-this.aStartAngle;0>c&&(c+=2*Math.PI),c>2*Math.PI&&(c-=2*Math.PI),b=this.aClockwise===!0?this.aEndAngle+(1-a)*(2*Math.PI-c):this.aStartAngle+a*c;var d=this.aX+this.xRadius*Math.cos(b),f=this.aY+this.yRadius*Math.sin(b);return new e.Vector2(d,f)},e.ArcCurve=function(a,b,c,d,f,g){e.EllipseCurve.call(this,a,b,c,c,d,f,g)},e.ArcCurve.prototype=Object.create(e.EllipseCurve.prototype),e.LineCurve3=e.Curve.create(function(a,b){this.v1=a,this.v2=b},function(a){var b=new e.Vector3;return b.subVectors(this.v2,this.v1),b.multiplyScalar(a),b.add(this.v1),b}),e.QuadraticBezierCurve3=e.Curve.create(function(a,b,c){this.v0=a,this.v1=b,this.v2=c},function(a){var b,c,d;return b=e.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x),c=e.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y),d=e.Shape.Utils.b2(a,this.v0.z,this.v1.z,this.v2.z),new e.Vector3(b,c,d)}),e.CubicBezierCurve3=e.Curve.create(function(a,b,c,d){this.v0=a,this.v1=b,this.v2=c,this.v3=d},function(a){var b,c,d;return b=e.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x),c=e.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y),d=e.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z),new e.Vector3(b,c,d)}),e.SplineCurve3=e.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b,c,d,f=new e.Vector3,g=[],h=this.points;b=(h.length-1)*a,c=Math.floor(b),d=b-c,g[0]=0==c?c:c-1,g[1]=c,g[2]=c>h.length-2?h.length-1:c+1,g[3]=c>h.length-3?h.length-1:c+2;var i=h[g[0]],j=h[g[1]],k=h[g[2]],l=h[g[3]];return f.x=e.Curve.Utils.interpolate(i.x,j.x,k.x,l.x,d),f.y=e.Curve.Utils.interpolate(i.y,j.y,k.y,l.y,d),f.z=e.Curve.Utils.interpolate(i.z,j.z,k.z,l.z,d),f}),e.ClosedSplineCurve3=e.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b,c,d,f=new e.Vector3,g=[],h=this.points;return b=(h.length-0)*a,c=Math.floor(b),d=b-c,c+=c>0?0:(Math.floor(Math.abs(c)/h.length)+1)*h.length,g[0]=(c-1)%h.length,g[1]=c%h.length,g[2]=(c+1)%h.length,g[3]=(c+2)%h.length,f.x=e.Curve.Utils.interpolate(h[g[0]].x,h[g[1]].x,h[g[2]].x,h[g[3]].x,d),f.y=e.Curve.Utils.interpolate(h[g[0]].y,h[g[1]].y,h[g[2]].y,h[g[3]].y,d),f.z=e.Curve.Utils.interpolate(h[g[0]].z,h[g[1]].z,h[g[2]].z,h[g[3]].z,d),f}),e.AnimationHandler=function(){var a=[],b={},c={};c.update=function(b){for(var c=0;ca;a++){var c=this.hierarchy[a];c.matrixAutoUpdate=!0,void 0===c.animationCache&&(c.animationCache={},c.animationCache.prevKey={pos:0,rot:0,scl:0},c.animationCache.nextKey={pos:0,rot:0,scl:0},c.animationCache.originalMatrix=c instanceof e.Bone?c.skinMatrix:c.matrix);var d=c.animationCache.prevKey,f=c.animationCache.nextKey;d.pos=this.data.hierarchy[a].keys[0],d.rot=this.data.hierarchy[a].keys[0],d.scl=this.data.hierarchy[a].keys[0],f.pos=this.getNextKeyWith("pos",a,1),f.rot=this.getNextKeyWith("rot",a,1),f.scl=this.getNextKeyWith("scl",a,1)}},e.Animation.prototype.update=function(){var a=[],b=new e.Vector3,c=function(a,b){var c,e,f,g,h,i,j,k,l,m=[],n=[];return c=(a.length-1)*b,e=Math.floor(c),f=c-e,m[0]=0===e?e:e-1,m[1]=e,m[2]=e>a.length-2?e:e+1,m[3]=e>a.length-3?e:e+2,i=a[m[0]],j=a[m[1]],k=a[m[2]],l=a[m[3]],g=f*f,h=f*g,n[0]=d(i[0],j[0],k[0],l[0],f,g,h),n[1]=d(i[1],j[1],k[1],l[1],f,g,h),n[2]=d(i[2],j[2],k[2],l[2],f,g,h),n},d=function(a,b,c,d,e,f,g){var h=.5*(c-a),i=.5*(d-b);return(2*(b-c)+h+i)*g+(-3*(b-c)-2*h-i)*f+h*e+b};return function(d){if(this.isPlaying!==!1){this.currentTime+=d*this.timeScale;var f,g=["pos","rot","scl"],h=this.data.length;if(this.loop===!0&&this.currentTime>h)this.currentTime%=h,this.reset();else if(this.loop===!1&&this.currentTime>h)return void this.stop();this.currentTime=Math.min(this.currentTime,h);for(var i=0,j=this.hierarchy.length;j>i;i++)for(var k=this.hierarchy[i],l=k.animationCache,m=0;3>m;m++){var n=g[m],o=l.prevKey[n],p=l.nextKey[n];if(p.time<=this.currentTime){for(o=this.data.hierarchy[i].keys[0],p=this.getNextKeyWith(n,i,1);p.timeo.index;)o=p,p=this.getNextKeyWith(n,i,p.index+1);l.prevKey[n]=o,l.nextKey[n]=p}k.matrixAutoUpdate=!0,k.matrixWorldNeedsUpdate=!0;var q=(this.currentTime-o.time)/(p.time-o.time),r=o[n],s=p[n];if(0>q&&(q=0),q>1&&(q=1),"pos"===n){if(f=k.position,this.interpolationType===e.AnimationHandler.LINEAR)f.x=r[0]+(s[0]-r[0])*q,f.y=r[1]+(s[1]-r[1])*q,f.z=r[2]+(s[2]-r[2])*q;else if(this.interpolationType===e.AnimationHandler.CATMULLROM||this.interpolationType===e.AnimationHandler.CATMULLROM_FORWARD){a[0]=this.getPrevKeyWith("pos",i,o.index-1).pos,a[1]=r,a[2]=s,a[3]=this.getNextKeyWith("pos",i,p.index+1).pos,q=.33*q+.33;var t=c(a,q);if(f.x=t[0],f.y=t[1],f.z=t[2],this.interpolationType===e.AnimationHandler.CATMULLROM_FORWARD){var u=c(a,1.01*q);b.set(u[0],u[1],u[2]),b.sub(f),b.y=0,b.normalize();var v=Math.atan2(b.x,b.z);k.rotation.set(0,v,0)}}}else"rot"===n?e.Quaternion.slerp(r,s,k.quaternion,q):"scl"===n&&(f=k.scale,f.x=r[0]+(s[0]-r[0])*q,f.y=r[1]+(s[1]-r[1])*q,f.z=r[2]+(s[2]-r[2])*q)}}}}(),e.Animation.prototype.getNextKeyWith=function(a,b,c){var d=this.data.hierarchy[b].keys;for(this.interpolationType===e.AnimationHandler.CATMULLROM||this.interpolationType===e.AnimationHandler.CATMULLROM_FORWARD?c=c0?c:0:c>=0?c:c+d.length;c>=0;c--)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[d.length-1]},e.KeyFrameAnimation=function(a,b){this.root=a,this.data=e.AnimationHandler.get(b),this.hierarchy=e.AnimationHandler.parse(a),this.currentTime=0,this.timeScale=.001,this.isPlaying=!1,this.isPaused=!0,this.loop=!0;for(var c=0,d=this.hierarchy.length;d>c;c++){var f=this.data.hierarchy[c].keys,g=this.data.hierarchy[c].sids,h=this.hierarchy[c];if(f.length&&g){for(var i=0;ib;b++){c=this.hierarchy[b],d=this.data.hierarchy[b],void 0===d.animationCache&&(d.animationCache={},d.animationCache.prevKey=null,d.animationCache.nextKey=null,d.animationCache.originalMatrix=c instanceof e.Bone?c.skinMatrix:c.matrix);var g=this.data.hierarchy[b].keys;g.length&&(d.animationCache.prevKey=g[0],d.animationCache.nextKey=g[1],this.startTime=Math.min(g[0].time,this.startTime),this.endTime=Math.max(g[g.length-1].time,this.endTime))}this.update(0)}this.isPaused=!1,e.AnimationHandler.addToUpdate(this)},e.KeyFrameAnimation.prototype.pause=function(){this.isPaused?e.AnimationHandler.addToUpdate(this):e.AnimationHandler.removeFromUpdate(this),this.isPaused=!this.isPaused},e.KeyFrameAnimation.prototype.stop=function(){this.isPlaying=!1,this.isPaused=!1,e.AnimationHandler.removeFromUpdate(this);for(var a=0;ab&&(this.currentTime%=b),this.currentTime=Math.min(this.currentTime,b);for(var c=0,d=this.hierarchy.length;d>c;c++){var e=this.hierarchy[c],f=this.data.hierarchy[c],g=f.keys,h=f.animationCache;if(g.length){var i=h.prevKey,j=h.nextKey;if(j.time<=this.currentTime){for(;j.timei.index;)i=j,j=g[i.index+1];h.prevKey=i,h.nextKey=j}j.time>=this.currentTime?i.interpolate(j,this.currentTime):i.interpolate(j,j.time),this.data.hierarchy[c].node.updateMatrix(),e.matrixWorldNeedsUpdate=!0}}}},e.KeyFrameAnimation.prototype.getNextKeyWith=function(a,b,c){var d=this.data.hierarchy[b].keys;for(c%=d.length;c=0?c:c+d.length;c>=0;c--)if(d[c].hasTarget(a))return d[c];return d[d.length-1]},e.MorphAnimation=function(a){this.mesh=a,this.frames=a.morphTargetInfluences.length,this.currentTime=0,this.duration=1e3,this.loop=!0,this.isPlaying=!1},e.MorphAnimation.prototype={play:function(){this.isPlaying=!0},pause:function(){this.isPlaying=!1},update:function(){var a=0,b=0;return function(c){if(this.isPlaying!==!1){this.currentTime+=c,this.loop===!0&&this.currentTime>this.duration&&(this.currentTime%=this.duration),this.currentTime=Math.min(this.currentTime,this.duration);var d=this.duration/this.frames,e=Math.floor(this.currentTime/d);e!=b&&(this.mesh.morphTargetInfluences[a]=0,this.mesh.morphTargetInfluences[b]=1,this.mesh.morphTargetInfluences[e]=0,a=b,b=e),this.mesh.morphTargetInfluences[e]=this.currentTime%d/d,this.mesh.morphTargetInfluences[a]=1-this.mesh.morphTargetInfluences[e]}}}()},e.CubeCamera=function(a,b,c){e.Object3D.call(this),this.className="CubeCamera";var d=90,f=1,g=new e.PerspectiveCamera(d,f,a,b);g.up.set(0,-1,0),g.lookAt(new e.Vector3(1,0,0)),this.add(g);var h=new e.PerspectiveCamera(d,f,a,b);h.up.set(0,-1,0),h.lookAt(new e.Vector3(-1,0,0)),this.add(h);var i=new e.PerspectiveCamera(d,f,a,b);i.up.set(0,0,1),i.lookAt(new e.Vector3(0,1,0)),this.add(i);var j=new e.PerspectiveCamera(d,f,a,b);j.up.set(0,0,-1),j.lookAt(new e.Vector3(0,-1,0)),this.add(j);var k=new e.PerspectiveCamera(d,f,a,b);k.up.set(0,-1,0),k.lookAt(new e.Vector3(0,0,1)),this.add(k);var l=new e.PerspectiveCamera(d,f,a,b);l.up.set(0,-1,0),l.lookAt(new e.Vector3(0,0,-1)),this.add(l),this.renderTarget=new e.WebGLRenderTargetCube(c,c,{format:e.RGBFormat,magFilter:e.LinearFilter,minFilter:e.LinearFilter}),this.updateCubeMap=function(a,b){var c=this.renderTarget,d=c.generateMipmaps;c.generateMipmaps=!1,c.activeCubeFace=0,a.render(b,g,c),c.activeCubeFace=1,a.render(b,h,c),c.activeCubeFace=2,a.render(b,i,c),c.activeCubeFace=3,a.render(b,j,c),c.activeCubeFace=4,a.render(b,k,c),c.generateMipmaps=d,c.activeCubeFace=5,a.render(b,l,c)}},e.CubeCamera.prototype=Object.create(e.Object3D.prototype),e.CombinedCamera=function(a,b,c,d,f,g,h){e.Camera.call(this),this.className="CombinedCamera",this.fov=c,this.left=-a/2,this.right=a/2,this.top=b/2,this.bottom=-b/2,this.cameraO=new e.OrthographicCamera(a/-2,a/2,b/2,b/-2,g,h),this.cameraP=new e.PerspectiveCamera(c,a/b,d,f),this.zoom=1,this.toPerspective()},e.CombinedCamera.prototype=Object.create(e.Camera.prototype),e.CombinedCamera.prototype.toPerspective=function(){this.near=this.cameraP.near,this.far=this.cameraP.far,this.cameraP.fov=this.fov/this.zoom,this.cameraP.updateProjectionMatrix(),this.projectionMatrix=this.cameraP.projectionMatrix,this.inPerspectiveMode=!0,this.inOrthographicMode=!1},e.CombinedCamera.prototype.toOrthographic=function(){var a=this.fov,b=this.cameraP.aspect,c=this.cameraP.near,d=this.cameraP.far,e=(c+d)/2,f=Math.tan(a/2)*e,g=2*f,h=g*b,i=h/2;f/=this.zoom,i/=this.zoom,this.cameraO.left=-i,this.cameraO.right=i,this.cameraO.top=f,this.cameraO.bottom=-f,this.cameraO.updateProjectionMatrix(),this.near=this.cameraO.near,this.far=this.cameraO.far,this.projectionMatrix=this.cameraO.projectionMatrix,this.inPerspectiveMode=!1,this.inOrthographicMode=!0},e.CombinedCamera.prototype.setSize=function(a,b){this.cameraP.aspect=a/b,this.left=-a/2,this.right=a/2,this.top=b/2,this.bottom=-b/2},e.CombinedCamera.prototype.setFov=function(a){this.fov=a,this.inPerspectiveMode?this.toPerspective():this.toOrthographic()},e.CombinedCamera.prototype.updateProjectionMatrix=function(){this.inPerspectiveMode?this.toPerspective():(this.toPerspective(),this.toOrthographic())},e.CombinedCamera.prototype.setLens=function(a,b){void 0===b&&(b=24);var c=2*e.Math.radToDeg(Math.atan(b/(2*a)));return this.setFov(c),c},e.CombinedCamera.prototype.setZoom=function(a){this.zoom=a,this.inPerspectiveMode?this.toPerspective():this.toOrthographic()},e.CombinedCamera.prototype.toFrontView=function(){this.rotation.x=0,this.rotation.y=0,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toBackView=function(){this.rotation.x=0,this.rotation.y=Math.PI,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toLeftView=function(){this.rotation.x=0,this.rotation.y=-Math.PI/2,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toRightView=function(){this.rotation.x=0,this.rotation.y=Math.PI/2,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toTopView=function(){this.rotation.x=-Math.PI/2,this.rotation.y=0,this.rotation.z=0,this.rotationAutoUpdate=!1},e.CombinedCamera.prototype.toBottomView=function(){this.rotation.x=Math.PI/2,this.rotation.y=0,this.rotation.z=0,this.rotationAutoUpdate=!1},e.BoxGeometry=function(a,b,c,d,f,g){function h(a,b,c,d,f,g,h,j){var k,l,m,n=i.widthSegments,o=i.heightSegments,p=f/2,q=g/2,r=i.vertices.length;"x"===a&&"y"===b||"y"===a&&"x"===b?k="z":"x"===a&&"z"===b||"z"===a&&"x"===b?(k="y",o=i.depthSegments):("z"===a&&"y"===b||"y"===a&&"z"===b)&&(k="x",n=i.depthSegments);var s=n+1,t=o+1,u=f/n,v=g/o,w=new e.Vector3;for(w[k]=h>0?1:-1,m=0;t>m;m++)for(l=0;s>l;l++){var x=new e.Vector3;x[a]=(l*u-p)*c,x[b]=(m*v-q)*d,x[k]=h,i.vertices.push(x)}for(m=0;o>m;m++)for(l=0;n>l;l++){var y=l+s*m,z=l+s*(m+1),A=l+1+s*(m+1),B=l+1+s*m,C=new e.Vector2(l/n,1-m/o),D=new e.Vector2(l/n,1-(m+1)/o),E=new e.Vector2((l+1)/n,1-(m+1)/o),F=new e.Vector2((l+1)/n,1-m/o),G=new e.Face3(y+r,z+r,B+r);G.normal.copy(w),G.vertexNormals.push(w.clone(),w.clone(),w.clone()),G.materialIndex=j,i.faces.push(G),i.faceVertexUvs[0].push([C,D,F]),G=new e.Face3(z+r,A+r,B+r),G.normal.copy(w),G.vertexNormals.push(w.clone(),w.clone(),w.clone()),G.materialIndex=j,i.faces.push(G),i.faceVertexUvs[0].push([D.clone(),E,F.clone()])}}e.Geometry.call(this),this.className="BoxGeometry";var i=this;this.width=a,this.height=b,this.depth=c,this.widthSegments=d||1,this.heightSegments=f||1,this.depthSegments=g||1;var j=this.width/2,k=this.height/2,l=this.depth/2;h("z","y",-1,-1,this.depth,this.height,j,0),h("z","y",1,-1,this.depth,this.height,-j,1),h("x","z",1,1,this.width,this.depth,k,2),h("x","z",1,-1,this.width,this.depth,-k,3),h("x","y",1,-1,this.width,this.height,l,4),h("x","y",-1,-1,this.width,this.height,-l,5),this.computeCentroids(),this.mergeVertices()},e.BoxGeometry.prototype=Object.create(e.Geometry.prototype),e.CircleGeometry=function(a,b,c,d){e.Geometry.call(this),this.className="CircleGeometry",this.radius=a=a||50,this.segments=b=void 0!==b?Math.max(3,b):8,this.thetaStart=c=void 0!==c?c:0,this.thetaLength=d=void 0!==d?d:2*Math.PI;var f,g=[],h=new e.Vector3,i=new e.Vector2(.5,.5);for(this.vertices.push(h),g.push(i),f=0;b>=f;f++){var j=new e.Vector3,k=c+f/b*d;j.x=a*Math.cos(k),j.y=a*Math.sin(k),this.vertices.push(j),g.push(new e.Vector2((j.x/a+1)/2,(j.y/a+1)/2))}var l=new e.Vector3(0,0,1);for(f=1;b>=f;f++){var m=f,n=f+1,o=0;this.faces.push(new e.Face3(m,n,o,[l.clone(),l.clone(),l.clone()])),this.faceVertexUvs[0].push([g[f].clone(),g[f+1].clone(),i.clone()])}this.computeCentroids(),this.computeFaceNormals(),this.boundingSphere=new e.Sphere(new e.Vector3,a)},e.CircleGeometry.prototype=Object.create(e.Geometry.prototype),e.CubeGeometry=e.BoxGeometry,e.CylinderGeometry=function(a,b,c,d,f,g){e.Geometry.call(this),this.className="CylinderGeometry",this.radiusTop=a=void 0!==a?a:20,this.radiusBottom=b=void 0!==b?b:20,this.height=c=void 0!==c?c:100,this.radialSegments=d=d||8,this.heightSegments=f=f||1,this.openEnded=g=void 0!==g?g:!1;var h,i,j=c/2,k=[],l=[];for(i=0;f>=i;i++){var m=[],n=[],o=i/f,p=o*(b-a)+a;for(h=0;d>=h;h++){var q=h/d,r=new e.Vector3;r.x=p*Math.sin(q*Math.PI*2),r.y=-o*c+j,r.z=p*Math.cos(q*Math.PI*2),this.vertices.push(r),m.push(this.vertices.length-1),n.push(new e.Vector2(q,1-o))}k.push(m),l.push(n)}var s,t,u=(b-a)/c;for(h=0;d>h;h++)for(0!==a?(s=this.vertices[k[0][h]].clone(),t=this.vertices[k[0][h+1]].clone()):(s=this.vertices[k[1][h]].clone(),t=this.vertices[k[1][h+1]].clone()),s.setY(Math.sqrt(s.x*s.x+s.z*s.z)*u).normalize(),t.setY(Math.sqrt(t.x*t.x+t.z*t.z)*u).normalize(),i=0;f>i;i++){var v=k[i][h],w=k[i+1][h],x=k[i+1][h+1],y=k[i][h+1],z=s.clone(),A=s.clone(),B=t.clone(),C=t.clone(),D=l[i][h].clone(),E=l[i+1][h].clone(),F=l[i+1][h+1].clone(),G=l[i][h+1].clone();this.faces.push(new e.Face3(v,w,y,[z,A,C])),this.faceVertexUvs[0].push([D,E,G]),this.faces.push(new e.Face3(w,x,y,[A.clone(),B,C.clone()])),this.faceVertexUvs[0].push([E.clone(),F,G.clone()])}if(g===!1&&a>0)for(this.vertices.push(new e.Vector3(0,j,0)),h=0;d>h;h++){var v=k[0][h],w=k[0][h+1],x=this.vertices.length-1,z=new e.Vector3(0,1,0),A=new e.Vector3(0,1,0),B=new e.Vector3(0,1,0),D=l[0][h].clone(),E=l[0][h+1].clone(),F=new e.Vector2(E.x,0);this.faces.push(new e.Face3(v,w,x,[z,A,B])),this.faceVertexUvs[0].push([D,E,F])}if(g===!1&&b>0)for(this.vertices.push(new e.Vector3(0,-j,0)),h=0;d>h;h++){var v=k[i][h+1],w=k[i][h],x=this.vertices.length-1,z=new e.Vector3(0,-1,0),A=new e.Vector3(0,-1,0),B=new e.Vector3(0,-1,0),D=l[i][h+1].clone(),E=l[i][h].clone(),F=new e.Vector2(E.x,1);this.faces.push(new e.Face3(v,w,x,[z,A,B])),this.faceVertexUvs[0].push([D,E,F])}this.computeCentroids(),this.computeFaceNormals()},e.CylinderGeometry.prototype=Object.create(e.Geometry.prototype),e.ExtrudeGeometry=function(a,b){return"undefined"==typeof a?void(a=[]):(e.Geometry.call(this),this.className="ExtrudeGeometry",a=a instanceof Array?a:[a],this.shapebb=a[a.length-1].getBoundingBox(),this.addShapeList(a,b),this.computeCentroids(),void this.computeFaceNormals())},e.ExtrudeGeometry.prototype=Object.create(e.Geometry.prototype),e.ExtrudeGeometry.prototype.addShapeList=function(a,b){for(var c=a.length,d=0;c>d;d++){var e=a[d];this.addShape(e,b)}},e.ExtrudeGeometry.prototype.addShape=function(a,b){function c(a,b,c){return b?b.clone().multiplyScalar(c).add(a):e.onerror("die, vec not specified")}function d(a,b,c){var d,f,g=1e-10,h=e.Math.sign,i=1,j=a.x-b.x,k=a.y-b.y,l=c.x-a.x,m=c.y-a.y,n=j*j+k*k,o=j*m-k*l;if(Math.abs(o)>g){var p=Math.sqrt(n),q=Math.sqrt(l*l+m*m),r=b.x-k/p,s=b.y+j/p,t=c.x-m/q,u=c.y+l/q,v=((t-r)*m-(u-s)*l)/(j*m-k*l);d=r+j*v-a.x,f=s+k*v-a.y;var w=d*d+f*f;if(2>=w)return new e.Vector2(d,f);i=Math.sqrt(w/2)}else{var x=!1;j>g?l>g&&(x=!0):-g>j?-g>l&&(x=!0):h(k)==h(m)&&(x=!0),x?(d=-k,f=j,i=Math.sqrt(n)):(d=j,f=k,i=Math.sqrt(n/2))}return new e.Vector2(d/i,f/i)}function f(){if(u){var a=0,b=T*a;for(W=0;U>W;W++)S=L[W],j(S[2]+b,S[1]+b,S[0]+b,!0);for(a=w+2*t,b=T*a,W=0;U>W;W++)S=L[W],j(S[0]+b,S[1]+b,S[2]+b,!1)}else{for(W=0;U>W;W++)S=L[W],j(S[2],S[1],S[0],!0);for(W=0;U>W;W++)S=L[W],j(S[0]+T*w,S[1]+T*w,S[2]+T*w,!1)}}function g(){var a=0;for(h(M,a),a+=M.length,D=0,E=J.length;E>D;D++)C=J[D],h(C,a),a+=C.length}function h(a,b){var c,d;for(W=a.length;--W>=0;){c=W,d=W-1,0>d&&(d=a.length-1);var e=0,f=w+2*t;for(e=0;f>e;e++){var g=T*e,h=T*(e+1),i=b+c+g,j=b+d+g,l=b+d+h,m=b+c+h;k(i,j,l,m,a,e,f,c,d)}}}function i(a,b,c){F.vertices.push(new e.Vector3(a,b,c))}function j(c,d,f,g){c+=G,d+=G,f+=G,F.faces.push(new e.Face3(c,d,f,null,null,z));var h=g?B.generateBottomUV(F,a,b,c,d,f):B.generateTopUV(F,a,b,c,d,f);F.faceVertexUvs[0].push(h)}function k(c,d,f,g,h,i,j,k,l){c+=G,d+=G,f+=G,g+=G,F.faces.push(new e.Face3(c,d,g,null,null,A)),F.faces.push(new e.Face3(d,f,g,null,null,A));var m=B.generateSideWallUV(F,a,h,b,c,d,f,g,i,j,k,l);F.faceVertexUvs[0].push([m[0],m[1],m[3]]),F.faceVertexUvs[0].push([m[1],m[2],m[3]])}var l,m,n,o,p,q=void 0!==b.amount?b.amount:100,r=void 0!==b.bevelThickness?b.bevelThickness:6,s=void 0!==b.bevelSize?b.bevelSize:r-2,t=void 0!==b.bevelSegments?b.bevelSegments:3,u=void 0!==b.bevelEnabled?b.bevelEnabled:!0,v=void 0!==b.curveSegments?b.curveSegments:12,w=void 0!==b.steps?b.steps:1,x=b.extrudePath,y=!1,z=b.material,A=b.extrudeMaterial,B=void 0!==b.UVGenerator?b.UVGenerator:e.ExtrudeGeometry.WorldUVGenerator;this.shapebb;x&&(l=x.getSpacedPoints(w),y=!0,u=!1,m=void 0!==b.frames?b.frames:new e.TubeGeometry.FrenetFrames(x,w,!1),n=new e.Vector3,o=new e.Vector3,p=new e.Vector3),u||(t=0,r=0,s=0);var C,D,E,F=this,G=this.vertices.length,H=a.extractPoints(v),I=H.shape,J=H.holes,K=!e.Shape.Utils.isClockWise(I);if(K){for(I=I.reverse(),D=0,E=J.length;E>D;D++)C=J[D],e.Shape.Utils.isClockWise(C)&&(J[D]=C.reverse());K=!1}var L=e.Shape.Utils.triangulateShape(I,J),M=I;for(D=0,E=J.length;E>D;D++)C=J[D],I=I.concat(C);for(var N,O,P,Q,R,S,T=I.length,U=L.length,V=(M.length,180/Math.PI,[]),W=0,X=M.length,Y=X-1,Z=W+1;X>W;W++,Y++,Z++){Y===X&&(Y=0),Z===X&&(Z=0);M[W],M[Y],M[Z];V[W]=d(M[W],M[Y],M[Z])}var $,_=[],aa=V.concat();for(D=0,E=J.length;E>D;D++){for(C=J[D],$=[],W=0,X=C.length,Y=X-1,Z=W+1;X>W;W++,Y++,Z++)Y===X&&(Y=0),Z===X&&(Z=0),$[W]=d(C[W],C[Y],C[Z]);_.push($),aa=aa.concat($)}for(N=0;t>N;N++){for(P=N/t,Q=r*(1-P),O=s*Math.sin(P*Math.PI/2),W=0,X=M.length;X>W;W++)R=c(M[W],V[W],O),i(R.x,R.y,-Q);for(D=0,E=J.length;E>D;D++)for(C=J[D],$=_[D],W=0,X=C.length;X>W;W++)R=c(C[W],$[W],O),i(R.x,R.y,-Q)}for(O=s,W=0;T>W;W++)R=u?c(I[W],aa[W],O):I[W],y?(o.copy(m.normals[0]).multiplyScalar(R.x),n.copy(m.binormals[0]).multiplyScalar(R.y),p.copy(l[0]).add(o).add(n),i(p.x,p.y,p.z)):i(R.x,R.y,0);var ba;for(ba=1;w>=ba;ba++)for(W=0;T>W;W++)R=u?c(I[W],aa[W],O):I[W],y?(o.copy(m.normals[ba]).multiplyScalar(R.x),n.copy(m.binormals[ba]).multiplyScalar(R.y),p.copy(l[ba]).add(o).add(n),i(p.x,p.y,p.z)):i(R.x,R.y,q/w*ba);for(N=t-1;N>=0;N--){for(P=N/t,Q=r*(1-P),O=s*Math.sin(P*Math.PI/2),W=0,X=M.length;X>W;W++)R=c(M[W],V[W],O),i(R.x,R.y,q+Q);for(D=0,E=J.length;E>D;D++)for(C=J[D],$=_[D],W=0,X=C.length;X>W;W++)R=c(C[W],$[W],O),y?i(R.x,R.y+l[w-1].y,l[w-1].x+Q):i(R.x,R.y,q+Q)}f(),g()},e.ExtrudeGeometry.WorldUVGenerator={generateTopUV:function(a,b,c,d,f,g){var h=a.vertices[d].x,i=a.vertices[d].y,j=a.vertices[f].x,k=a.vertices[f].y,l=a.vertices[g].x,m=a.vertices[g].y; return[new e.Vector2(h,i),new e.Vector2(j,k),new e.Vector2(l,m)]},generateBottomUV:function(a,b,c,d,e,f){return this.generateTopUV(a,b,c,d,e,f)},generateSideWallUV:function(a,b,c,d,f,g,h,i,j,k,l,m){var n=a.vertices[f].x,o=a.vertices[f].y,p=a.vertices[f].z,q=a.vertices[g].x,r=a.vertices[g].y,s=a.vertices[g].z,t=a.vertices[h].x,u=a.vertices[h].y,v=a.vertices[h].z,w=a.vertices[i].x,x=a.vertices[i].y,y=a.vertices[i].z;return Math.abs(o-r)<.01?[new e.Vector2(n,1-p),new e.Vector2(q,1-s),new e.Vector2(t,1-v),new e.Vector2(w,1-y)]:[new e.Vector2(o,1-p),new e.Vector2(r,1-s),new e.Vector2(u,1-v),new e.Vector2(x,1-y)]}},e.ExtrudeGeometry.__v1=new e.Vector2,e.ExtrudeGeometry.__v2=new e.Vector2,e.ExtrudeGeometry.__v3=new e.Vector2,e.ExtrudeGeometry.__v4=new e.Vector2,e.ExtrudeGeometry.__v5=new e.Vector2,e.ExtrudeGeometry.__v6=new e.Vector2,e.ShapeGeometry=function(a,b){e.Geometry.call(this),this.className="ShapeGeometry",a instanceof Array==!1&&(a=[a]),this.shapebb=a[a.length-1].getBoundingBox(),this.addShapeList(a,b),this.computeCentroids(),this.computeFaceNormals()},e.ShapeGeometry.prototype=Object.create(e.Geometry.prototype),e.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;d>c;c++)this.addShape(a[c],b);return this},e.ShapeGeometry.prototype.addShape=function(a,b){void 0===b&&(b={});var c,d,f,g=void 0!==b.curveSegments?b.curveSegments:12,h=b.material,i=void 0===b.UVGenerator?e.ExtrudeGeometry.WorldUVGenerator:b.UVGenerator,j=(this.shapebb,this.vertices.length),k=a.extractPoints(g),l=k.shape,m=k.holes,n=!e.Shape.Utils.isClockWise(l);if(n){for(l=l.reverse(),c=0,d=m.length;d>c;c++)f=m[c],e.Shape.Utils.isClockWise(f)&&(m[c]=f.reverse());n=!1}var o=e.Shape.Utils.triangulateShape(l,m),p=l;for(c=0,d=m.length;d>c;c++)f=m[c],l=l.concat(f);var q,r,s=l.length,t=o.length;p.length;for(c=0;s>c;c++)q=l[c],this.vertices.push(new e.Vector3(q.x,q.y,0));for(c=0;t>c;c++){r=o[c];var u=r[0]+j,v=r[1]+j,w=r[2]+j;this.faces.push(new e.Face3(u,v,w,null,null,h)),this.faceVertexUvs[0].push(i.generateBottomUV(this,a,b,u,v,w))}},e.LatheGeometry=function(a,b,c,d){e.Geometry.call(this),this.className="LatheGeometry",b=b||12,c=c||0,d=d||2*Math.PI;for(var f=1/(a.length-1),g=1/b,h=0,i=b;i>=h;h++)for(var j=c+h*g*d,k=Math.cos(j),l=Math.sin(j),m=0,n=a.length;n>m;m++){var o=a[m],p=new e.Vector3;p.x=k*o.x-l*o.y,p.y=l*o.x+k*o.y,p.z=o.z,this.vertices.push(p)}for(var q=a.length,h=0,i=b;i>h;h++)for(var m=0,n=a.length-1;n>m;m++){var r=m+q*h,s=r,t=r+q,k=r+1+q,u=r+1,v=h*g,w=m*f,x=v+g,y=w+f;this.faces.push(new e.Face3(s,t,u)),this.faceVertexUvs[0].push([new e.Vector2(v,w),new e.Vector2(x,w),new e.Vector2(v,y)]),this.faces.push(new e.Face3(t,k,u)),this.faceVertexUvs[0].push([new e.Vector2(x,w),new e.Vector2(x,y),new e.Vector2(v,y)])}this.mergeVertices(),this.computeCentroids(),this.computeFaceNormals(),this.computeVertexNormals()},e.LatheGeometry.prototype=Object.create(e.Geometry.prototype),e.PlaneGeometry=function(a,b,c,d){e.Geometry.call(this),this.className="PlaneGeometry",this.width=a,this.height=b,this.widthSegments=c||1,this.heightSegments=d||1;var f,g,h=a/2,i=b/2,j=this.widthSegments,k=this.heightSegments,l=j+1,m=k+1,n=this.width/j,o=this.height/k,p=new e.Vector3(0,0,1);for(g=0;m>g;g++)for(f=0;l>f;f++){var q=f*n-h,r=g*o-i;this.vertices.push(new e.Vector3(q,-r,0))}for(g=0;k>g;g++)for(f=0;j>f;f++){var s=f+l*g,t=f+l*(g+1),u=f+1+l*(g+1),v=f+1+l*g,w=new e.Vector2(f/j,1-g/k),x=new e.Vector2(f/j,1-(g+1)/k),y=new e.Vector2((f+1)/j,1-(g+1)/k),z=new e.Vector2((f+1)/j,1-g/k),A=new e.Face3(s,t,v);A.normal.copy(p),A.vertexNormals.push(p.clone(),p.clone(),p.clone()),this.faces.push(A),this.faceVertexUvs[0].push([w,x,z]),A=new e.Face3(t,u,v),A.normal.copy(p),A.vertexNormals.push(p.clone(),p.clone(),p.clone()),this.faces.push(A),this.faceVertexUvs[0].push([x.clone(),y,z.clone()])}this.computeCentroids()},e.PlaneGeometry.prototype=Object.create(e.Geometry.prototype),e.RingGeometry=function(a,b,c,d,f,g){e.Geometry.call(this),this.className="RingGeometry",a=a||0,b=b||50,f=void 0!==f?f:0,g=void 0!==g?g:2*Math.PI,c=void 0!==c?Math.max(3,c):8,d=void 0!==d?Math.max(3,d):8;var h,i,j=[],k=a,l=(b-a)/d;for(h=0;d>=h;h++){for(i=0;c>=i;i++){var m=new e.Vector3,n=f+i/c*g;m.x=k*Math.cos(n),m.y=k*Math.sin(n),this.vertices.push(m),j.push(new e.Vector2((m.x/b+1)/2,(m.y/b+1)/2))}k+=l}var o=new e.Vector3(0,0,1);for(h=0;d>h;h++){var p=h*c;for(i=0;c>=i;i++){var n=i+p,q=n+h,r=n+c+h,s=n+c+1+h;this.faces.push(new e.Face3(q,r,s,[o.clone(),o.clone(),o.clone()])),this.faceVertexUvs[0].push([j[q].clone(),j[r].clone(),j[s].clone()]),q=n+h,r=n+c+1+h,s=n+1+h,this.faces.push(new e.Face3(q,r,s,[o.clone(),o.clone(),o.clone()])),this.faceVertexUvs[0].push([j[q].clone(),j[r].clone(),j[s].clone()])}}this.computeCentroids(),this.computeFaceNormals(),this.boundingSphere=new e.Sphere(new e.Vector3,k)},e.RingGeometry.prototype=Object.create(e.Geometry.prototype),e.SphereGeometry=function(a,b,c,d,f,g,h){e.Geometry.call(this),this.className="SphereGeometry",this.radius=a=a||50,this.widthSegments=b=Math.max(3,Math.floor(b)||8),this.heightSegments=c=Math.max(2,Math.floor(c)||6),this.phiStart=d=void 0!==d?d:0,this.phiLength=f=void 0!==f?f:2*Math.PI,this.thetaStart=g=void 0!==g?g:0,this.thetaLength=h=void 0!==h?h:Math.PI;var i,j,k=[],l=[];for(j=0;c>=j;j++){var m=[],n=[];for(i=0;b>=i;i++){var o=i/b,p=j/c,q=new e.Vector3;q.x=-a*Math.cos(d+o*f)*Math.sin(g+p*h),q.y=a*Math.cos(g+p*h),q.z=a*Math.sin(d+o*f)*Math.sin(g+p*h),this.vertices.push(q),m.push(this.vertices.length-1),n.push(new e.Vector2(o,1-p))}k.push(m),l.push(n)}for(j=0;jp;p++)for(this.grid[p]=[],k=p/(C-1),o=a.getPointAt(k),h=F[p],i=G[p],j=H[p],q=0;q=h&&(g=h,m.set(1,0,0)),g>=i&&(g=i,m.set(0,1,0)),g>=j&&m.set(0,0,1),q.crossVectors(n[0],m).normalize(),o[0].crossVectors(n[0],q),p[0].crossVectors(n[0],o[0])}var f,g,h,i,j,k,l,m=(new e.Vector3,new e.Vector3),n=(new e.Vector3,[]),o=[],p=[],q=new e.Vector3,r=new e.Matrix4,s=b+1,t=1e-4;for(this.tangents=n,this.normals=o,this.binormals=p,k=0;s>k;k++)l=k/(s-1),n[k]=a.getTangentAt(l),n[k].normalize();for(d(),k=1;s>k;k++)o[k]=o[k-1].clone(),p[k]=p[k-1].clone(),q.crossVectors(n[k-1],n[k]),q.length()>t&&(q.normalize(),f=Math.acos(e.Math.clamp(n[k-1].dot(n[k]),-1,1)),o[k].applyMatrix4(r.makeRotationAxis(q,f))),p[k].crossVectors(n[k],o[k]);if(c)for(f=Math.acos(e.Math.clamp(o[0].dot(o[s-1]),-1,1)),f/=s-1,n[0].dot(q.crossVectors(o[0],o[s-1]))>0&&(f=-f),k=1;s>k;k++)o[k].applyMatrix4(r.makeRotationAxis(n[k],f*k)),p[k].crossVectors(n[k],o[k])},e.PolyhedronGeometry=function(a,b,c,d){function f(a){var b=a.normalize().clone();b.index=l.vertices.push(b)-1;var c=i(a)/2/Math.PI+.5,d=j(a)/Math.PI+.5;return b.uv=new e.Vector2(c,1-d),b}function g(a,b,c){var d=new e.Face3(a.index,b.index,c.index,[a.clone(),b.clone(),c.clone()]);d.centroid.add(a).add(b).add(c).divideScalar(3),l.faces.push(d);var f=i(d.centroid);l.faceVertexUvs[0].push([k(a.uv,a,f),k(b.uv,b,f),k(c.uv,c,f)])}function h(a,b){for(var c=Math.pow(2,b),d=(Math.pow(4,b),f(l.vertices[a.a])),e=f(l.vertices[a.b]),h=f(l.vertices[a.c]),i=[],j=0;c>=j;j++){i[j]=[];for(var k=f(d.clone().lerp(h,j/c)),m=f(e.clone().lerp(h,j/c)),n=c-j,o=0;n>=o;o++)0==o&&j==c?i[j][o]=k:i[j][o]=f(k.clone().lerp(m,o/n))}for(var j=0;c>j;j++)for(var o=0;2*(c-j)-1>o;o++){var p=Math.floor(o/2);o%2==0?g(i[j][p+1],i[j+1][p],i[j][p]):g(i[j][p+1],i[j+1][p+1],i[j+1][p])}}function i(a){return Math.atan2(a.z,-a.x)}function j(a){return Math.atan2(-a.y,Math.sqrt(a.x*a.x+a.z*a.z))}function k(a,b,c){return 0>c&&1===a.x&&(a=new e.Vector2(a.x-1,a.y)),0===b.x&&0===b.z&&(a=new e.Vector2(c/2/Math.PI+.5,a.y)),a.clone()}e.Geometry.call(this),this.className="PolyhedronGeometry",c=c||1,d=d||0;for(var l=this,m=0,n=a.length;n>m;m++)f(new e.Vector3(a[m][0],a[m][1],a[m][2]));for(var o=this.vertices,p=[],m=0,n=b.length;n>m;m++){var q=o[b[m][0]],r=o[b[m][1]],s=o[b[m][2]];p[m]=new e.Face3(q.index,r.index,s.index,[q.clone(),r.clone(),s.clone()])}for(var m=0,n=p.length;n>m;m++)h(p[m],d);for(var m=0,n=this.faceVertexUvs[0].length;n>m;m++){var t=this.faceVertexUvs[0][m],u=t[0].x,v=t[1].x,w=t[2].x,x=Math.max(u,Math.max(v,w)),y=Math.min(u,Math.min(v,w));x>.9&&.1>y&&(.2>u&&(t[0].x+=1),.2>v&&(t[1].x+=1),.2>w&&(t[2].x+=1))}for(var m=0,n=this.vertices.length;n>m;m++)this.vertices[m].multiplyScalar(c);this.mergeVertices(),this.computeCentroids(),this.computeFaceNormals(),this.boundingSphere=new e.Sphere(new e.Vector3,c)},e.PolyhedronGeometry.prototype=Object.create(e.Geometry.prototype),e.IcosahedronGeometry=function(a,b){this.radius=a,this.detail=b;var c=(1+Math.sqrt(5))/2,d=[[-1,c,0],[1,c,0],[-1,-c,0],[1,-c,0],[0,-1,c],[0,1,c],[0,-1,-c],[0,1,-c],[c,0,-1],[c,0,1],[-c,0,-1],[-c,0,1]],f=[[0,11,5],[0,5,1],[0,1,7],[0,7,10],[0,10,11],[1,5,9],[5,11,4],[11,10,2],[10,7,6],[7,1,8],[3,9,4],[3,4,2],[3,2,6],[3,6,8],[3,8,9],[4,9,5],[2,4,11],[6,2,10],[8,6,7],[9,8,1]];e.PolyhedronGeometry.call(this,d,f,a,b),this.className="IcosahedronGeometry"},e.IcosahedronGeometry.prototype=Object.create(e.Geometry.prototype),e.OctahedronGeometry=function(a,b){var c=[[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]],d=[[0,2,4],[0,4,3],[0,3,5],[0,5,2],[1,2,5],[1,5,3],[1,3,4],[1,4,2]];e.PolyhedronGeometry.call(this,c,d,a,b),this.className="OctahedronGeometry"},e.OctahedronGeometry.prototype=Object.create(e.Geometry.prototype),e.TetrahedronGeometry=function(a,b){this.className="TetrahedronGeometry";var c=[[1,1,1],[-1,-1,1],[-1,1,-1],[1,-1,-1]],d=[[2,1,0],[0,3,2],[1,3,0],[2,3,1]];e.PolyhedronGeometry.call(this,c,d,a,b)},e.TetrahedronGeometry.prototype=Object.create(e.Geometry.prototype),e.ParametricGeometry=function(a,b,c){e.Geometry.call(this),this.className="ParametricGeometry";var d,f,g,h,i,j=this.vertices,k=this.faces,l=this.faceVertexUvs[0],m=b+1;for(d=0;c>=d;d++)for(i=d/c,f=0;b>=f;f++)h=f/b,g=a(h,i),j.push(g);var n,o,p,q,r,s,t,u;for(d=0;c>d;d++)for(f=0;b>f;f++)n=d*m+f,o=d*m+f+1,p=(d+1)*m+f+1,q=(d+1)*m+f,r=new e.Vector2(f/b,d/c),s=new e.Vector2((f+1)/b,d/c),t=new e.Vector2((f+1)/b,(d+1)/c),u=new e.Vector2(f/b,(d+1)/c),k.push(new e.Face3(n,o,q)),l.push([r,s,u]),k.push(new e.Face3(o,p,q)),l.push([s.clone(),t,u.clone()]);this.computeCentroids(),this.computeFaceNormals(),this.computeVertexNormals()},e.ParametricGeometry.prototype=Object.create(e.Geometry.prototype),e.AxisHelper=function(a){a=a||1;var b=new e.Geometry;b.vertices.push(new e.Vector3,new e.Vector3(a,0,0),new e.Vector3,new e.Vector3(0,a,0),new e.Vector3,new e.Vector3(0,0,a)),b.colors.push(new e.Color(16711680),new e.Color(16755200),new e.Color(65280),new e.Color(11206400),new e.Color(255),new e.Color(43775));var c=new e.LineBasicMaterial({vertexColors:e.VertexColors});e.Line.call(this,b,c,e.LinePieces),this.className="AxisHelper"},e.AxisHelper.prototype=Object.create(e.Line.prototype),e.ArrowHelper=function(a,b,c,d,f,g){e.Object3D.call(this),this.className="ArrowHelper",void 0===d&&(d=16776960),void 0===c&&(c=1),void 0===f&&(f=.2*c),void 0===g&&(g=.2*f),this.position=b;var h=new e.Geometry;h.vertices.push(new e.Vector3(0,0,0)),h.vertices.push(new e.Vector3(0,1,0)),this.line=new e.Line(h,new e.LineBasicMaterial({color:d})),this.line.matrixAutoUpdate=!1,this.add(this.line);var i=new e.CylinderGeometry(0,.5,1,5,1);i.applyMatrix((new e.Matrix4).makeTranslation(0,-.5,0)),this.cone=new e.Mesh(i,new e.MeshBasicMaterial({color:d})),this.cone.matrixAutoUpdate=!1,this.add(this.cone),this.setDirection(a),this.setLength(c,f,g)},e.ArrowHelper.prototype=Object.create(e.Object3D.prototype),e.ArrowHelper.prototype.setDirection=function(){var a,b=new e.Vector3;return function(c){c.y>.99999?this.quaternion.set(0,0,0,1):c.y<-.99999?this.quaternion.set(1,0,0,0):(b.set(c.z,0,-c.x).normalize(),a=Math.acos(c.y),this.quaternion.setFromAxisAngle(b,a))}}(),e.ArrowHelper.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a),void 0===c&&(c=.2*b),this.line.scale.set(1,a,1),this.line.updateMatrix(),this.cone.scale.set(c,b,c),this.cone.position.y=a,this.cone.updateMatrix()},e.ArrowHelper.prototype.setColor=function(a){this.line.material.color.setHex(a),this.cone.material.color.setHex(a)},e.BoxHelper=function(a){var b=[new e.Vector3(1,1,1),new e.Vector3(-1,1,1),new e.Vector3(-1,-1,1),new e.Vector3(1,-1,1),new e.Vector3(1,1,-1),new e.Vector3(-1,1,-1),new e.Vector3(-1,-1,-1),new e.Vector3(1,-1,-1)];this.vertices=b;var c=new e.Geometry;c.vertices.push(b[0],b[1],b[1],b[2],b[2],b[3],b[3],b[0],b[4],b[5],b[5],b[6],b[6],b[7],b[7],b[4],b[0],b[4],b[1],b[5],b[2],b[6],b[3],b[7]),e.Line.call(this,c,new e.LineBasicMaterial({color:16776960}),e.LinePieces),void 0!==a&&this.update(a)},e.BoxHelper.prototype=Object.create(e.Line.prototype),e.BoxHelper.prototype.update=function(a){var b=a.geometry;null===b.boundingBox&&b.computeBoundingBox();var c=b.boundingBox.min,d=b.boundingBox.max,e=this.vertices;e[0].set(d.x,d.y,d.z),e[1].set(c.x,d.y,d.z),e[2].set(c.x,c.y,d.z),e[3].set(d.x,c.y,d.z),e[4].set(d.x,d.y,c.z),e[5].set(c.x,d.y,c.z),e[6].set(c.x,c.y,c.z),e[7].set(d.x,c.y,c.z),this.geometry.computeBoundingSphere(),this.geometry.verticesNeedUpdate=!0,this.matrixAutoUpdate=!1,this.matrixWorld=a.matrixWorld},e.BoundingBoxHelper=function(a,b){var c=void 0!==b?b:8947848;this.object=a,this.box=new e.Box3,e.Mesh.call(this,new e.BoxGeometry(1,1,1),new e.MeshBasicMaterial({color:c,wireframe:!0}))},e.BoundingBoxHelper.prototype=Object.create(e.Mesh.prototype),e.BoundingBoxHelper.prototype.update=function(){this.box.setFromObject(this.object),this.box.size(this.scale),this.box.center(this.position)},e.CameraHelper=function(a){function b(a,b,d){c(a,d),c(b,d)}function c(a,b){d.vertices.push(new e.Vector3),d.colors.push(new e.Color(b)),void 0===g[a]&&(g[a]=[]),g[a].push(d.vertices.length-1)}var d=new e.Geometry,f=new e.LineBasicMaterial({color:16777215,vertexColors:e.FaceColors}),g={},h=16755200,i=16711680,j=43775,k=16777215,l=3355443;b("n1","n2",h),b("n2","n4",h),b("n4","n3",h),b("n3","n1",h),b("f1","f2",h),b("f2","f4",h),b("f4","f3",h),b("f3","f1",h),b("n1","f1",h),b("n2","f2",h),b("n3","f3",h),b("n4","f4",h),b("p","n1",i),b("p","n2",i),b("p","n3",i),b("p","n4",i),b("u1","u2",j),b("u2","u3",j),b("u3","u1",j),b("c","t",k),b("p","c",l),b("cn1","cn2",l),b("cn3","cn4",l),b("cf1","cf2",l),b("cf3","cf4",l),e.Line.call(this,d,f,e.LinePieces),this.camera=a,this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1,this.pointMap=g,this.update()},e.CameraHelper.prototype=Object.create(e.Line.prototype),e.CameraHelper.prototype.update=function(){var a=new e.Vector3,b=new e.Camera,c=new e.Projector;return function(){function d(d,f,g,h){a.set(f,g,h),c.unprojectVector(a,b);var i=e.pointMap[d];if(void 0!==i)for(var j=0,k=i.length;k>j;j++)e.geometry.vertices[i[j]].copy(a)}var e=this,f=1,g=1;b.projectionMatrix.copy(this.camera.projectionMatrix),d("c",0,0,-1),d("t",0,0,1),d("n1",-f,-g,-1),d("n2",f,-g,-1),d("n3",-f,g,-1),d("n4",f,g,-1),d("f1",-f,-g,1),d("f2",f,-g,1),d("f3",-f,g,1),d("f4",f,g,1),d("u1",.7*f,1.1*g,-1),d("u2",.7*-f,1.1*g,-1),d("u3",0,2*g,-1),d("cf1",-f,0,1),d("cf2",f,0,1),d("cf3",0,-g,1),d("cf4",0,g,1),d("cn1",-f,0,-1),d("cn2",f,0,-1),d("cn3",0,-g,-1),d("cn4",0,g,-1),this.geometry.verticesNeedUpdate=!0}}(),e.DirectionalLightHelper=function(a,b){e.Object3D.call(this),this.light=a,this.light.updateMatrixWorld(),this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1,b=b||1;var c=new e.PlaneGeometry(b,b),d=new e.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity),this.lightPlane=new e.Mesh(c,d),this.add(this.lightPlane),c=new e.Geometry,c.vertices.push(new e.Vector3),c.vertices.push(new e.Vector3),d=new e.LineBasicMaterial({fog:!1}),d.color.copy(this.light.color).multiplyScalar(this.light.intensity),this.targetLine=new e.Line(c,d),this.add(this.targetLine),this.update()},e.DirectionalLightHelper.prototype=Object.create(e.Object3D.prototype),e.DirectionalLightHelper.prototype.dispose=function(){this.lightPlane.geometry.dispose(),this.lightPlane.material.dispose(),this.targetLine.geometry.dispose(),this.targetLine.material.dispose()},e.DirectionalLightHelper.prototype.update=function(){var a=new e.Vector3,b=new e.Vector3,c=new e.Vector3;return function(){a.setFromMatrixPosition(this.light.matrixWorld),b.setFromMatrixPosition(this.light.target.matrixWorld),c.subVectors(b,a),this.lightPlane.lookAt(c),this.lightPlane.material.color.copy(this.light.color).multiplyScalar(this.light.intensity),this.targetLine.geometry.vertices[1].copy(c),this.targetLine.geometry.verticesNeedUpdate=!0,this.targetLine.material.color.copy(this.lightPlane.material.color)}}(),e.EdgesHelper=function(a,b){var c=void 0!==b?b:16777215,d=[0,0],f={},g=function(a,b){return a-b},h=["a","b","c"],i=new e.BufferGeometry,j=a.geometry.clone();j.mergeVertices(),j.computeFaceNormals();for(var k=j.vertices,l=j.faces,m=0,n=0,o=l.length;o>n;n++)for(var p=l[n],q=0;3>q;q++){d[0]=p[h[q]],d[1]=p[h[(q+1)%3]],d.sort(g);var r=d.toString();void 0===f[r]?(f[r]={vert1:d[0],vert2:d[1],face1:n,face2:void 0},m++):f[r].face2=n}i.addAttribute("position",Float32Array,2*m,3);var s=i.attributes.position.array,t=0;for(var r in f){var u=f[r];if(void 0===u.face2||l[u.face1].normal.dot(l[u.face2].normal)<.9999){var v=k[u.vert1];s[t++]=v.x,s[t++]=v.y,s[t++]=v.z,v=k[u.vert2],s[t++]=v.x,s[t++]=v.y,s[t++]=v.z}}e.Line.call(this,i,new e.LineBasicMaterial({color:c}),e.LinePieces),this.matrixAutoUpdate=!1,this.matrixWorld=a.matrixWorld},e.EdgesHelper.prototype=Object.create(e.Line.prototype),e.FaceNormalsHelper=function(a,b,c,d){this.object=a,this.size=void 0!==b?b:1;for(var f=void 0!==c?c:16776960,g=void 0!==d?d:1,h=new e.Geometry,i=this.object.geometry.faces,j=0,k=i.length;k>j;j++)h.vertices.push(new e.Vector3),h.vertices.push(new e.Vector3);e.Line.call(this,h,new e.LineBasicMaterial({color:f,linewidth:g}),e.LinePieces),this.matrixAutoUpdate=!1,this.normalMatrix=new e.Matrix3,this.update()},e.FaceNormalsHelper.prototype=Object.create(e.Line.prototype),e.FaceNormalsHelper.prototype.update=function(a){var b=new e.Vector3;return function(a){this.object.updateMatrixWorld(!0),this.normalMatrix.getNormalMatrix(this.object.matrixWorld);for(var c=this.geometry.vertices,d=this.object.geometry.faces,e=this.object.matrixWorld,f=0,g=d.length;g>f;f++){var h=d[f];b.copy(h.normal).applyMatrix3(this.normalMatrix).normalize().multiplyScalar(this.size);var i=2*f;c[i].copy(h.centroid).applyMatrix4(e),c[i+1].addVectors(c[i],b)}return this.geometry.verticesNeedUpdate=!0,this}}(),e.GridHelper=function(a,b){var c=new e.Geometry,d=new e.LineBasicMaterial({vertexColors:e.VertexColors});this.color1=new e.Color(4473924),this.color2=new e.Color(8947848);for(var f=-a;a>=f;f+=b){c.vertices.push(new e.Vector3(-a,0,f),new e.Vector3(a,0,f),new e.Vector3(f,0,-a),new e.Vector3(f,0,a));var g=0===f?this.color1:this.color2;c.colors.push(g,g,g,g)}e.Line.call(this,c,d,e.LinePieces)},e.GridHelper.prototype=Object.create(e.Line.prototype),e.GridHelper.prototype.setColors=function(a,b){this.color1.set(a),this.color2.set(b),this.geometry.colorsNeedUpdate=!0},e.HemisphereLightHelper=function(a,b,c,d){e.Object3D.call(this),this.light=a,this.light.updateMatrixWorld(),this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1,this.colors=[new e.Color,new e.Color];var f=new e.SphereGeometry(b,4,2);f.applyMatrix((new e.Matrix4).makeRotationX(-Math.PI/2));for(var g=0,h=8;h>g;g++)f.faces[g].color=this.colors[4>g?0:1];var i=new e.MeshBasicMaterial({vertexColors:e.FaceColors,wireframe:!0});this.lightSphere=new e.Mesh(f,i),this.add(this.lightSphere),this.update()},e.HemisphereLightHelper.prototype=Object.create(e.Object3D.prototype),e.HemisphereLightHelper.prototype.dispose=function(){this.lightSphere.geometry.dispose(),this.lightSphere.material.dispose()},e.HemisphereLightHelper.prototype.update=function(){var a=new e.Vector3;return function(){this.colors[0].copy(this.light.color).multiplyScalar(this.light.intensity),this.colors[1].copy(this.light.groundColor).multiplyScalar(this.light.intensity),this.lightSphere.lookAt(a.setFromMatrixPosition(this.light.matrixWorld).negate()),this.lightSphere.geometry.colorsNeedUpdate=!0}}(),e.PointLightHelper=function(a,b){this.light=a,this.light.updateMatrixWorld();var c=new e.SphereGeometry(b,4,2),d=new e.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity),e.Mesh.call(this,c,d),this.matrixWorld=this.light.matrixWorld,this.matrixAutoUpdate=!1},e.PointLightHelper.prototype=Object.create(e.Mesh.prototype),e.PointLightHelper.prototype.dispose=function(){this.geometry.dispose(),this.material.dispose()},e.PointLightHelper.prototype.update=function(){this.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)},e.SpotLightHelper=function(a){e.Object3D.call(this),this.light=a,this.light.updateMatrixWorld(),this.matrixWorld=a.matrixWorld,this.matrixAutoUpdate=!1;var b=new e.CylinderGeometry(0,1,1,8,1,!0);b.applyMatrix((new e.Matrix4).makeTranslation(0,-.5,0)),b.applyMatrix((new e.Matrix4).makeRotationX(-Math.PI/2));var c=new e.MeshBasicMaterial({wireframe:!0,fog:!1});this.cone=new e.Mesh(b,c),this.add(this.cone),this.update()},e.SpotLightHelper.prototype=Object.create(e.Object3D.prototype),e.SpotLightHelper.prototype.dispose=function(){this.cone.geometry.dispose(),this.cone.material.dispose()},e.SpotLightHelper.prototype.update=function(){var a=new e.Vector3,b=new e.Vector3;return function(){var c=this.light.distance?this.light.distance:1e4,d=c*Math.tan(this.light.angle);this.cone.scale.set(d,d,c),a.setFromMatrixPosition(this.light.matrixWorld),b.setFromMatrixPosition(this.light.target.matrixWorld),this.cone.lookAt(b.sub(a)),this.cone.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)}}(),e.VertexNormalsHelper=function(a,b,c,d){this.object=a,this.size=void 0!==b?b:1;for(var f=void 0!==c?c:16711680,g=void 0!==d?d:1,h=new e.Geometry,i=(a.geometry.vertices,a.geometry.faces),j=0,k=i.length;k>j;j++)for(var l=i[j],m=0,n=l.vertexNormals.length;n>m;m++)h.vertices.push(new e.Vector3),h.vertices.push(new e.Vector3);e.Line.call(this,h,new e.LineBasicMaterial({color:f,linewidth:g}),e.LinePieces),this.matrixAutoUpdate=!1,this.normalMatrix=new e.Matrix3,this.update()},e.VertexNormalsHelper.prototype=Object.create(e.Line.prototype),e.VertexNormalsHelper.prototype.update=function(a){var b=new e.Vector3;return function(a){var c=["a","b","c","d"];this.object.updateMatrixWorld(!0),this.normalMatrix.getNormalMatrix(this.object.matrixWorld);for(var d=this.geometry.vertices,e=this.object.geometry.vertices,f=this.object.geometry.faces,g=this.object.matrixWorld,h=0,i=0,j=f.length;j>i;i++)for(var k=f[i],l=0,m=k.vertexNormals.length;m>l;l++){var n=k[c[l]],o=e[n],p=k.vertexNormals[l];d[h].copy(o).applyMatrix4(g),b.copy(p).applyMatrix3(this.normalMatrix).normalize().multiplyScalar(this.size),b.add(d[h]),h+=1,d[h].copy(b),h+=1}return this.geometry.verticesNeedUpdate=!0,this}}(),e.VertexTangentsHelper=function(a,b,c,d){this.object=a,this.size=void 0!==b?b:1;for(var f=void 0!==c?c:255,g=void 0!==d?d:1,h=new e.Geometry,i=(a.geometry.vertices,a.geometry.faces),j=0,k=i.length;k>j;j++)for(var l=i[j],m=0,n=l.vertexTangents.length;n>m;m++)h.vertices.push(new e.Vector3),h.vertices.push(new e.Vector3);e.Line.call(this,h,new e.LineBasicMaterial({color:f,linewidth:g}),e.LinePieces),this.matrixAutoUpdate=!1,this.update()},e.VertexTangentsHelper.prototype=Object.create(e.Line.prototype),e.VertexTangentsHelper.prototype.update=function(a){var b=new e.Vector3;return function(a){var c=["a","b","c","d"];this.object.updateMatrixWorld(!0);for(var d=this.geometry.vertices,e=this.object.geometry.vertices,f=this.object.geometry.faces,g=this.object.matrixWorld,h=0,i=0,j=f.length;j>i;i++)for(var k=f[i],l=0,m=k.vertexTangents.length;m>l;l++){var n=k[c[l]],o=e[n],p=k.vertexTangents[l];d[h].copy(o).applyMatrix4(g),b.copy(p).transformDirection(g).multiplyScalar(this.size),b.add(d[h]),h+=1,d[h].copy(b),h+=1}return this.geometry.verticesNeedUpdate=!0,this}}(),e.WireframeHelper=function(a,b){var c=void 0!==b?b:16777215,d=[0,0],f={},g=function(a,b){return a-b},h=["a","b","c"],i=new e.BufferGeometry;if(a.geometry instanceof e.Geometry){for(var j=a.geometry.vertices,k=a.geometry.faces,l=0,m=new Uint32Array(6*k.length),n=0,o=k.length;o>n;n++)for(var p=k[n],q=0;3>q;q++){d[0]=p[h[q]],d[1]=p[h[(q+1)%3]],d.sort(g);var r=d.toString();void 0===f[r]&&(m[2*l]=d[0],m[2*l+1]=d[1],f[r]=!0,l++)}i.addAttribute("position",Float32Array,2*l,3);for(var s=i.attributes.position.array,n=0,o=l;o>n;n++)for(var q=0;2>q;q++){var t=j[m[2*n+q]],u=6*n+3*q;s[u+0]=t.x,s[u+1]=t.y,s[u+2]=t.z}}else if(a.geometry instanceof e.BufferGeometry&&void 0!==a.geometry.attributes.index){for(var j=a.geometry.attributes.position.array,v=a.geometry.attributes.index.array,w=a.geometry.offsets,l=0,m=new Uint32Array(2*v.length),x=0,y=w.length;y>x;++x)for(var z=w[x].start,A=w[x].count,u=w[x].index,n=z,B=z+A;B>n;n+=3)for(var q=0;3>q;q++){d[0]=u+v[n+q],d[1]=u+v[n+(q+1)%3],d.sort(g);var r=d.toString();void 0===f[r]&&(m[2*l]=d[0],m[2*l+1]=d[1],f[r]=!0,l++)}i.addAttribute("position",Float32Array,2*l,3);for(var s=i.attributes.position.array,n=0,o=l;o>n;n++)for(var q=0;2>q;q++){var u=6*n+3*q,C=3*m[2*n+q];s[u+0]=j[C],s[u+1]=j[C+1],s[u+2]=j[C+2]}}else if(a.geometry instanceof e.BufferGeometry){var j=a.geometry.attributes.position.array,l=j.length/3,D=l/3;i.addAttribute("position",Float32Array,2*l,3);for(var s=i.attributes.position.array,n=0,o=D;o>n;n++)for(var q=0;3>q;q++){var u=18*n+6*q,E=9*n+3*q;s[u+0]=j[E],s[u+1]=j[E+1],s[u+2]=j[E+2];var C=9*n+3*((q+1)%3);s[u+3]=j[C],s[u+4]=j[C+1],s[u+5]=j[C+2]}}e.Line.call(this,i,new e.LineBasicMaterial({color:c}),e.LinePieces),this.matrixAutoUpdate=!1,this.matrixWorld=a.matrixWorld},e.WireframeHelper.prototype=Object.create(e.Line.prototype),e.ImmediateRenderObject=function(){e.Object3D.call(this),this.render=function(a){}},e.ImmediateRenderObject.prototype=Object.create(e.Object3D.prototype),e.LensFlare=function(a,b,c,d,f){ e.Object3D.call(this),this.lensFlares=[],this.positionScreen=new e.Vector3,this.customUpdateCallback=void 0,void 0!==a&&this.add(a,b,c,d,f)},e.LensFlare.prototype=Object.create(e.Object3D.prototype),e.LensFlare.prototype.add=function(a,b,c,d,f,g){void 0===b&&(b=-1),void 0===c&&(c=0),void 0===g&&(g=1),void 0===f&&(f=new e.Color(16777215)),void 0===d&&(d=e.NormalBlending),c=Math.min(c,Math.max(0,c)),this.lensFlares.push({texture:a,size:b,distance:c,x:0,y:0,z:0,scale:1,rotation:1,opacity:g,color:f,blending:d})},e.LensFlare.prototype.updateLensFlares=function(){var a,b,c=this.lensFlares.length,d=2*-this.positionScreen.x,e=2*-this.positionScreen.y;for(a=0;c>a;a++)b=this.lensFlares[a],b.x=this.positionScreen.x+d*b.distance,b.y=this.positionScreen.y+e*b.distance,b.wantedRotation=b.x*Math.PI*.25,b.rotation+=.25*(b.wantedRotation-b.rotation)},e.MorphBlendMesh=function(a,b){e.Mesh.call(this,a,b),this.animationsMap={},this.animationsList=[];var c=this.geometry.morphTargets.length,d="__default",f=0,g=c-1,h=c/1;this.createAnimation(d,f,g,h),this.setAnimationWeight(d,1)},e.MorphBlendMesh.prototype=Object.create(e.Mesh.prototype),e.MorphBlendMesh.prototype.createAnimation=function(a,b,c,d){var e={startFrame:b,endFrame:c,length:c-b+1,fps:d,duration:(c-b)/d,lastFrame:0,currentFrame:0,active:!1,time:0,direction:1,weight:1,directionBackwards:!1,mirroredLoop:!1};this.animationsMap[a]=e,this.animationsList.push(e)},e.MorphBlendMesh.prototype.autoCreateAnimations=function(a){for(var b,c=/([a-z]+)(\d+)/,d={},e=this.geometry,f=0,g=e.morphTargets.length;g>f;f++){var h=e.morphTargets[f],i=h.name.match(c);if(i&&i.length>1){var j=i[1];i[2];d[j]||(d[j]={start:1/0,end:-(1/0)});var k=d[j];fk.end&&(k.end=f),b||(b=j)}}for(var j in d){var k=d[j];this.createAnimation(j,k.start,k.end,a)}this.firstAnimation=b},e.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){var b=this.animationsMap[a];b&&(b.direction=1,b.directionBackwards=!1)},e.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){var b=this.animationsMap[a];b&&(b.direction=-1,b.directionBackwards=!0)},e.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)},e.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)},e.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)},e.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)},e.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0,c=this.animationsMap[a];return c&&(b=c.time),b},e.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1,c=this.animationsMap[a];return c&&(b=c.duration),b},e.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):e.onwarning("animation["+a+"] undefined")},e.MorphBlendMesh.prototype.stopAnimation=function(a){var b=this.animationsMap[a];b&&(b.active=!1)},e.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;c>b;b++){var d=this.animationsList[b];if(d.active){var f=d.duration/d.length;d.time+=d.direction*a,d.mirroredLoop?(d.time>d.duration||d.time<0)&&(d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),d.time<0&&(d.time=0,d.directionBackwards=!1)):(d.time=d.time%d.duration,d.time<0&&(d.time+=d.duration));var g=d.startFrame+e.Math.clamp(Math.floor(d.time/f),0,d.length-1),h=d.weight;g!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*h,this.morphTargetInfluences[g]=0,d.lastFrame=d.currentFrame,d.currentFrame=g);var i=d.time%f/f;d.directionBackwards&&(i=1-i),this.morphTargetInfluences[d.currentFrame]=i*h,this.morphTargetInfluences[d.lastFrame]=(1-i)*h}}},e.LensFlarePlugin=function(){function a(a,c){var d=b.createProgram(),e=b.createShader(b.FRAGMENT_SHADER),f=b.createShader(b.VERTEX_SHADER),g="precision "+c+" float;\n";return b.shaderSource(e,g+a.fragmentShader),b.shaderSource(f,g+a.vertexShader),b.compileShader(e),b.compileShader(f),b.attachShader(d,e),b.attachShader(d,f),b.linkProgram(d),d}var b,c,d,f={};this.init=function(g){b=g.context,c=g,d=g.getPrecision(),f.vertices=new Float32Array(16),f.faces=new Uint16Array(6);var h=0;f.vertices[h++]=-1,f.vertices[h++]=-1,f.vertices[h++]=0,f.vertices[h++]=0,f.vertices[h++]=1,f.vertices[h++]=-1,f.vertices[h++]=1,f.vertices[h++]=0,f.vertices[h++]=1,f.vertices[h++]=1,f.vertices[h++]=1,f.vertices[h++]=1,f.vertices[h++]=-1,f.vertices[h++]=1,f.vertices[h++]=0,f.vertices[h++]=1,h=0,f.faces[h++]=0,f.faces[h++]=1,f.faces[h++]=2,f.faces[h++]=0,f.faces[h++]=2,f.faces[h++]=3,f.vertexBuffer=b.createBuffer(),f.elementBuffer=b.createBuffer(),b.bindBuffer(b.ARRAY_BUFFER,f.vertexBuffer),b.bufferData(b.ARRAY_BUFFER,f.vertices,b.STATIC_DRAW),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,f.elementBuffer),b.bufferData(b.ELEMENT_ARRAY_BUFFER,f.faces,b.STATIC_DRAW),f.tempTexture=b.createTexture(),f.occlusionTexture=b.createTexture(),b.bindTexture(b.TEXTURE_2D,f.tempTexture),b.texImage2D(b.TEXTURE_2D,0,b.RGB,16,16,0,b.RGB,b.UNSIGNED_BYTE,null),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST),b.bindTexture(b.TEXTURE_2D,f.occlusionTexture),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,16,16,0,b.RGBA,b.UNSIGNED_BYTE,null),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST),b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST),b.getParameter(b.MAX_VERTEX_TEXTURE_IMAGE_UNITS)<=0?(f.hasVertexTexture=!1,f.program=a(e.ShaderFlares.lensFlare,d)):(f.hasVertexTexture=!0,f.program=a(e.ShaderFlares.lensFlareVertexTexture,d)),f.attributes={},f.uniforms={},f.attributes.vertex=b.getAttribLocation(f.program,"position"),f.attributes.uv=b.getAttribLocation(f.program,"uv"),f.uniforms.renderType=b.getUniformLocation(f.program,"renderType"),f.uniforms.map=b.getUniformLocation(f.program,"map"),f.uniforms.occlusionMap=b.getUniformLocation(f.program,"occlusionMap"),f.uniforms.opacity=b.getUniformLocation(f.program,"opacity"),f.uniforms.color=b.getUniformLocation(f.program,"color"),f.uniforms.scale=b.getUniformLocation(f.program,"scale"),f.uniforms.rotation=b.getUniformLocation(f.program,"rotation"),f.uniforms.screenPosition=b.getUniformLocation(f.program,"screenPosition")},this.render=function(a,d,g,h){var i=a.__webglFlares,j=i.length;if(j){var k=new e.Vector3,l=h/g,m=.5*g,n=.5*h,o=16/h,p=new e.Vector2(o*l,o),q=new e.Vector3(1,1,0),r=new e.Vector2(1,1),s=f.uniforms,t=f.attributes;b.useProgram(f.program),b.enableVertexAttribArray(f.attributes.vertex),b.enableVertexAttribArray(f.attributes.uv),b.uniform1i(s.occlusionMap,0),b.uniform1i(s.map,1),b.bindBuffer(b.ARRAY_BUFFER,f.vertexBuffer),b.vertexAttribPointer(t.vertex,2,b.FLOAT,!1,16,0),b.vertexAttribPointer(t.uv,2,b.FLOAT,!1,16,8),b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,f.elementBuffer),b.disable(b.CULL_FACE),b.depthMask(!1);var u,v,w,x,y;for(u=0;j>u;u++)if(o=16/h,p.set(o*l,o),x=i[u],k.set(x.matrixWorld.elements[12],x.matrixWorld.elements[13],x.matrixWorld.elements[14]),k.applyMatrix4(d.matrixWorldInverse),k.applyProjection(d.projectionMatrix),q.copy(k),r.x=q.x*m+m,r.y=q.y*n+n,f.hasVertexTexture||r.x>0&&r.x0&&r.yv;v++)y=x.lensFlares[v],y.opacity>.001&&y.scale>.001&&(q.x=y.x,q.y=y.y,q.z=y.z,o=y.size*y.scale/h,p.x=o*l,p.y=o,b.uniform3f(s.screenPosition,q.x,q.y,q.z),b.uniform2f(s.scale,p.x,p.y),b.uniform1f(s.rotation,y.rotation),b.uniform1f(s.opacity,y.opacity),b.uniform3f(s.color,y.color.r,y.color.g,y.color.b),c.setBlending(y.blending,y.blendEquation,y.blendSrc,y.blendDst),c.setTexture(y.texture,1),b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0));b.enable(b.CULL_FACE),b.enable(b.DEPTH_TEST),b.depthMask(!0)}}},e.ShadowMapPlugin=function(){function a(a,b){var c=new e.DirectionalLight;c.isVirtual=!0,c.onlyShadow=!0,c.castShadow=!0,c.shadowCameraNear=a.shadowCameraNear,c.shadowCameraFar=a.shadowCameraFar,c.shadowCameraLeft=a.shadowCameraLeft,c.shadowCameraRight=a.shadowCameraRight,c.shadowCameraBottom=a.shadowCameraBottom,c.shadowCameraTop=a.shadowCameraTop,c.shadowCameraVisible=a.shadowCameraVisible,c.shadowDarkness=a.shadowDarkness,c.shadowBias=a.shadowCascadeBias[b],c.shadowMapWidth=a.shadowCascadeWidth[b],c.shadowMapHeight=a.shadowCascadeHeight[b],c.pointsWorld=[],c.pointsFrustum=[];for(var d=c.pointsWorld,f=c.pointsFrustum,g=0;8>g;g++)d[g]=new e.Vector3,f[g]=new e.Vector3;var h=a.shadowCascadeNearZ[b],i=a.shadowCascadeFarZ[b];return f[0].set(-1,-1,h),f[1].set(1,-1,h),f[2].set(-1,1,h),f[3].set(1,1,h),f[4].set(-1,-1,i),f[5].set(1,-1,i),f[6].set(-1,1,i),f[7].set(1,1,i),c}function b(a,b){var c=a.shadowCascadeArray[b];c.position.copy(a.position),c.target.position.copy(a.target.position),c.lookAt(c.target),c.shadowCameraVisible=a.shadowCameraVisible,c.shadowDarkness=a.shadowDarkness,c.shadowBias=a.shadowCascadeBias[b];var d=a.shadowCascadeNearZ[b],e=a.shadowCascadeFarZ[b],f=c.pointsFrustum;f[0].z=d,f[1].z=d,f[2].z=d,f[3].z=d,f[4].z=e,f[5].z=e,f[6].z=e,f[7].z=e}function c(a,b){var c=b.shadowCamera,d=b.pointsFrustum,f=b.pointsWorld;n.set(1/0,1/0,1/0),o.set(-(1/0),-(1/0),-(1/0));for(var g=0;8>g;g++){var h=f[g];h.copy(d[g]),e.ShadowMapPlugin.__projector.unprojectVector(h,a),h.applyMatrix4(c.matrixWorldInverse),h.xo.x&&(o.x=h.x),h.yo.y&&(o.y=h.y),h.zo.z&&(o.z=h.z)}c.left=n.x,c.right=o.x,c.top=o.y,c.bottom=n.y,c.updateProjectionMatrix()}function d(a){return a.material instanceof e.MeshFaceMaterial?a.material.materials[0]:a.material}var f,g,h,i,j,k,l=new e.Frustum,m=new e.Matrix4,n=new e.Vector3,o=new e.Vector3,p=new e.Vector3;this.init=function(a){f=a.context,g=a;var b=e.ShaderLib.depthRGBA,c=e.UniformsUtils.clone(b.uniforms);h=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c}),i=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c,morphTargets:!0}),j=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c,skinning:!0}),k=new e.ShaderMaterial({fragmentShader:b.fragmentShader,vertexShader:b.vertexShader,uniforms:c,morphTargets:!0,skinning:!0}),h._shadowPass=!0,i._shadowPass=!0,j._shadowPass=!0,k._shadowPass=!0},this.render=function(a,b){g.shadowMapEnabled&&g.shadowMapAutoUpdate&&this.update(a,b)},this.update=function(n,o){var q,r,s,t,u,v,w,x,y,z,A,B,C,D,E=[],F=0,G=null;for(f.clearColor(1,1,1,1),f.disable(f.BLEND),f.enable(f.CULL_FACE),f.frontFace(f.CCW),g.shadowMapCullFace===e.CullFaceFront?f.cullFace(f.FRONT):f.cullFace(f.BACK),g.setDepthTest(!0),q=0,r=n.__lights.length;r>q;q++)if(C=n.__lights[q],C.castShadow)if(C instanceof e.DirectionalLight&&C.shadowCascade)for(u=0;uq;q++){if(C=E[q],!C.shadowMap){var J=e.NearestFilter;g.shadowMapType===e.PCFSoftShadowMap&&(J=e.NearestFilter);var K={minFilter:J,magFilter:J,format:e.RGBAFormat};C.shadowMap=new e.WebGLRenderTarget(C.shadowMapWidth,C.shadowMapHeight,K),C.shadowMapSize=new e.Vector2(C.shadowMapWidth,C.shadowMapHeight),C.shadowMatrix=new e.Matrix4}if(!C.shadowCamera){if(C instanceof e.SpotLight)C.shadowCamera=new e.PerspectiveCamera(C.shadowCameraFov,C.shadowMapWidth/C.shadowMapHeight,C.shadowCameraNear,C.shadowCameraFar);else{if(!(C instanceof e.DirectionalLight)){e.onerror("Unsupported light type for shadow");continue}C.shadowCamera=new e.OrthographicCamera(C.shadowCameraLeft,C.shadowCameraRight,C.shadowCameraTop,C.shadowCameraBottom,C.shadowCameraNear,C.shadowCameraFar)}n.add(C.shadowCamera),n.autoUpdate===!0&&n.updateMatrixWorld()}for(C.shadowCameraVisible&&!C.cameraHelper&&(C.cameraHelper=new e.CameraHelper(C.shadowCamera),C.shadowCamera.add(C.cameraHelper)),C.isVirtual&&H.originalCamera==o&&c(o,C),v=C.shadowMap,w=C.shadowMatrix,x=C.shadowCamera,x.position.setFromMatrixPosition(C.matrixWorld),p.setFromMatrixPosition(C.target.matrixWorld),x.lookAt(p),x.updateMatrixWorld(),x.matrixWorldInverse.getInverse(x.matrixWorld),C.cameraHelper&&(C.cameraHelper.visible=C.shadowCameraVisible),C.shadowCameraVisible&&C.cameraHelper.update(),w.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1),w.multiply(x.projectionMatrix),w.multiply(x.matrixWorldInverse),m.multiplyMatrices(x.projectionMatrix,x.matrixWorldInverse),l.setFromMatrix(m),g.setRenderTarget(v),g.clear(),D=n.__webglObjects,s=0,t=D.length;t>s;s++)A=D[s],B=A.object,A.render=!1,B.visible&&B.castShadow&&((B instanceof e.Mesh||B instanceof e.ParticleSystem)&&B.frustumCulled&&!l.intersectsObject(B)||(B._modelViewMatrix.multiplyMatrices(x.matrixWorldInverse,B.matrixWorld),A.render=!0));var L,M,N;for(s=0,t=D.length;t>s;s++)A=D[s],A.render&&(B=A.object,y=A.buffer,L=d(B),M=void 0!==B.geometry.morphTargets&&B.geometry.morphTargets.length>0&&L.morphTargets,N=B instanceof e.SkinnedMesh&&L.skinning,z=B.customDepthMaterial?B.customDepthMaterial:N?M?k:j:M?i:h,y instanceof e.BufferGeometry?g.renderBufferDirect(x,n.__lights,G,z,y,B):g.renderBuffer(x,n.__lights,G,z,y,B));for(D=n.__webglObjectsImmediate,s=0,t=D.length;t>s;s++)A=D[s],B=A.object,B.visible&&B.castShadow&&(B._modelViewMatrix.multiplyMatrices(x.matrixWorldInverse,B.matrixWorld),g.renderImmediateObject(x,n.__lights,G,h,B))}var O=g.getClearColor(),P=g.getClearAlpha();f.clearColor(O.r,O.g,O.b,P),f.enable(f.BLEND),g.shadowMapCullFace===e.CullFaceFront&&f.cullFace(f.BACK)}},e.ShadowMapPlugin.__projector=new e.Projector,e.SpritePlugin=function(){function a(){var a=c.createProgram(),b=c.createShader(c.VERTEX_SHADER),e=c.createShader(c.FRAGMENT_SHADER);return c.shaderSource(b,["precision "+d.getPrecision()+" float;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform float rotation;","uniform vec2 scale;","uniform vec2 uvOffset;","uniform vec2 uvScale;","attribute vec2 position;","attribute vec2 uv;","varying vec2 vUV;","void main() {","vUV = uvOffset + uv * uvScale;","vec2 alignedPosition = position * scale;","vec2 rotatedPosition;","rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;","rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;","vec4 finalPosition;","finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );","finalPosition.xy += rotatedPosition;","finalPosition = projectionMatrix * finalPosition;","gl_Position = finalPosition;","}"].join("\n")),c.shaderSource(e,["precision "+d.getPrecision()+" float;","uniform vec3 color;","uniform sampler2D map;","uniform float opacity;","uniform int fogType;","uniform vec3 fogColor;","uniform float fogDensity;","uniform float fogNear;","uniform float fogFar;","uniform float alphaTest;","varying vec2 vUV;","void main() {","vec4 texture = texture2D( map, vUV );","if ( texture.a < alphaTest ) discard;","gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );","if ( fogType > 0 ) {","float depth = gl_FragCoord.z / gl_FragCoord.w;","float fogFactor = 0.0;","if ( fogType == 1 ) {","fogFactor = smoothstep( fogNear, fogFar, depth );","} else {","const float LOG2 = 1.442695;","float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );","fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );","}","gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );","}","}"].join("\n")),c.compileShader(b),c.compileShader(e),c.attachShader(a,b),c.attachShader(a,e),c.linkProgram(a),a}function b(a,b){return a.z!==b.z?b.z-a.z:b.id-a.id}var c,d,f,g,h,i,j,k,l,m;this.init=function(b){c=b.context,d=b,g=new Float32Array([-.5,-.5,0,0,.5,-.5,1,0,.5,.5,1,1,-.5,.5,0,1]),h=new Uint16Array([0,1,2,0,2,3]),i=c.createBuffer(),j=c.createBuffer(),c.bindBuffer(c.ARRAY_BUFFER,i),c.bufferData(c.ARRAY_BUFFER,g,c.STATIC_DRAW),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,j),c.bufferData(c.ELEMENT_ARRAY_BUFFER,h,c.STATIC_DRAW),k=a(),l={position:c.getAttribLocation(k,"position"),uv:c.getAttribLocation(k,"uv")},m={uvOffset:c.getUniformLocation(k,"uvOffset"),uvScale:c.getUniformLocation(k,"uvScale"),rotation:c.getUniformLocation(k,"rotation"),scale:c.getUniformLocation(k,"scale"),color:c.getUniformLocation(k,"color"),map:c.getUniformLocation(k,"map"),opacity:c.getUniformLocation(k,"opacity"),modelViewMatrix:c.getUniformLocation(k,"modelViewMatrix"),projectionMatrix:c.getUniformLocation(k,"projectionMatrix"),fogType:c.getUniformLocation(k,"fogType"),fogDensity:c.getUniformLocation(k,"fogDensity"),fogNear:c.getUniformLocation(k,"fogNear"),fogFar:c.getUniformLocation(k,"fogFar"),fogColor:c.getUniformLocation(k,"fogColor"),alphaTest:c.getUniformLocation(k,"alphaTest")};var n=document.createElement("canvas");n.width=8,n.height=8;var o=n.getContext("2d");o.fillStyle="#ffffff",o.fillRect(0,0,n.width,n.height),f=new e.Texture(n),f.needsUpdate=!0},this.render=function(a,g,h,n){var o=a.__webglSprites,p=o.length;if(p){c.useProgram(k),c.enableVertexAttribArray(l.position),c.enableVertexAttribArray(l.uv),c.disable(c.CULL_FACE),c.enable(c.BLEND),c.bindBuffer(c.ARRAY_BUFFER,i),c.vertexAttribPointer(l.position,2,c.FLOAT,!1,16,0),c.vertexAttribPointer(l.uv,2,c.FLOAT,!1,16,8),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,j),c.uniformMatrix4fv(m.projectionMatrix,!1,g.projectionMatrix.elements),c.activeTexture(c.TEXTURE0),c.uniform1i(m.map,0);var q=0,r=0,s=a.fog;s?(c.uniform3f(m.fogColor,s.color.r,s.color.g,s.color.b),s instanceof e.Fog?(c.uniform1f(m.fogNear,s.near),c.uniform1f(m.fogFar,s.far),c.uniform1i(m.fogType,1),q=1,r=1):s instanceof e.FogExp2&&(c.uniform1f(m.fogDensity,s.density),c.uniform1i(m.fogType,2),q=2,r=2)):(c.uniform1i(m.fogType,0),q=0,r=0);var t,u,v,w,x=[];for(t=0;p>t;t++)u=o[t],v=u.material,u.visible!==!1&&(u._modelViewMatrix.multiplyMatrices(g.matrixWorldInverse,u.matrixWorld),u.z=-u._modelViewMatrix.elements[14]);for(o.sort(b),t=0;p>t;t++)u=o[t],u.visible!==!1&&(v=u.material,c.uniform1f(m.alphaTest,v.alphaTest),c.uniformMatrix4fv(m.modelViewMatrix,!1,u._modelViewMatrix.elements),x[0]=u.scale.x,x[1]=u.scale.y,w=a.fog&&v.fog?r:0,q!==w&&(c.uniform1i(m.fogType,w),q=w),null!==v.map?(c.uniform2f(m.uvOffset,v.map.offset.x,v.map.offset.y),c.uniform2f(m.uvScale,v.map.repeat.x,v.map.repeat.y)):(c.uniform2f(m.uvOffset,0,0),c.uniform2f(m.uvScale,1,1)),c.uniform1f(m.opacity,v.opacity),c.uniform3f(m.color,v.color.r,v.color.g,v.color.b),c.uniform1f(m.rotation,v.rotation),c.uniform2fv(m.scale,x),d.setBlending(v.blending,v.blendEquation,v.blendSrc,v.blendDst),d.setDepthTest(v.depthTest),d.setDepthWrite(v.depthWrite),v.map&&v.map.image&&v.map.image.width?d.setTexture(v.map,0):d.setTexture(f,0),c.drawElements(c.TRIANGLES,6,c.UNSIGNED_SHORT,0));c.enable(c.CULL_FACE)}}},e.DepthPassPlugin=function(){function a(a){return a.material instanceof e.MeshFaceMaterial?a.material.materials[0]:a.material}this.enabled=!1,this.renderTarget=null;var b,c,d,f,g,h,i=new e.Frustum,j=new e.Matrix4;this.init=function(a){b=a.context,c=a;var i=e.ShaderLib.depthRGBA,j=e.UniformsUtils.clone(i.uniforms);d=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j}),f=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j,morphTargets:!0}),g=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j,skinning:!0}),h=new e.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:j,morphTargets:!0,skinning:!0}),d._shadowPass=!0,f._shadowPass=!0,g._shadowPass=!0,h._shadowPass=!0},this.render=function(a,b){this.enabled&&this.update(a,b)},this.update=function(k,l){var m,n,o,p,q,r,s,t=null;for(b.clearColor(1,1,1,1),b.disable(b.BLEND),c.setDepthTest(!0),k.autoUpdate===!0&&k.updateMatrixWorld(),l.matrixWorldInverse.getInverse(l.matrixWorld),j.multiplyMatrices(l.projectionMatrix,l.matrixWorldInverse),i.setFromMatrix(j),c.setRenderTarget(this.renderTarget),c.clear(),s=k.__webglObjects,m=0,n=s.length;n>m;m++)q=s[m],r=q.object,q.render=!1,r.visible&&((r instanceof e.Mesh||r instanceof e.ParticleSystem)&&r.frustumCulled&&!i.intersectsObject(r)||(r._modelViewMatrix.multiplyMatrices(l.matrixWorldInverse,r.matrixWorld),q.render=!0));var u,v,w;for(m=0,n=s.length;n>m;m++)if(q=s[m],q.render){if(r=q.object,o=q.buffer,r instanceof e.ParticleSystem&&!r.customDepthMaterial)continue;u=a(r),u&&c.setMaterialFaces(r.material),v=r.geometry.morphTargets.length>0&&u.morphTargets,w=r instanceof e.SkinnedMesh&&u.skinning,p=r.customDepthMaterial?r.customDepthMaterial:w?v?h:g:v?f:d,o instanceof e.BufferGeometry?c.renderBufferDirect(l,k.__lights,t,p,o,r):c.renderBuffer(l,k.__lights,t,p,o,r)}for(s=k.__webglObjectsImmediate,m=0,n=s.length;n>m;m++)q=s[m],r=q.object,r.visible&&(r._modelViewMatrix.multiplyMatrices(l.matrixWorldInverse,r.matrixWorld),c.renderImmediateObject(l,k.__lights,t,d,r));var x=c.getClearColor(),y=c.getClearAlpha();b.clearColor(x.r,x.g,x.b,y),b.enable(b.BLEND)}},e.ShaderFlares={lensFlareVertexTexture:{vertexShader:["uniform lowp int renderType;","uniform vec3 screenPosition;","uniform vec2 scale;","uniform float rotation;","uniform sampler2D occlusionMap;","attribute vec2 position;","attribute vec2 uv;","varying vec2 vUV;","varying float vVisibility;","void main() {","vUV = uv;","vec2 pos = position;","if( renderType == 2 ) {","vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );","visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );","visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );","visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );","visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );","visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );","visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );","visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );","visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );","vVisibility = visibility.r / 9.0;","vVisibility *= 1.0 - visibility.g / 9.0;","vVisibility *= visibility.b / 9.0;","vVisibility *= 1.0 - visibility.a / 9.0;","pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;","pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;","}","gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );","}"].join("\n"),fragmentShader:["uniform lowp int renderType;","uniform sampler2D map;","uniform float opacity;","uniform vec3 color;","varying vec2 vUV;","varying float vVisibility;","void main() {","if( renderType == 0 ) {","gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );","} else if( renderType == 1 ) {","gl_FragColor = texture2D( map, vUV );","} else {","vec4 texture = texture2D( map, vUV );","texture.a *= opacity * vVisibility;","gl_FragColor = texture;","gl_FragColor.rgb *= color;","}","}"].join("\n")},lensFlare:{vertexShader:["uniform lowp int renderType;","uniform vec3 screenPosition;","uniform vec2 scale;","uniform float rotation;","attribute vec2 position;","attribute vec2 uv;","varying vec2 vUV;","void main() {","vUV = uv;","vec2 pos = position;","if( renderType == 2 ) {","pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;","pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;","}","gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );","}"].join("\n"),fragmentShader:["precision mediump float;","uniform lowp int renderType;","uniform sampler2D map;","uniform sampler2D occlusionMap;","uniform float opacity;","uniform vec3 color;","varying vec2 vUV;","void main() {","if( renderType == 0 ) {","gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );","} else if( renderType == 1 ) {","gl_FragColor = texture2D( map, vUV );","} else {","float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;","visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;","visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;","visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;","visibility = ( 1.0 - visibility / 4.0 );","vec4 texture = texture2D( map, vUV );","texture.a *= opacity * visibility;","gl_FragColor = texture;","gl_FragColor.rgb *= color;","}","}"].join("\n")}},"undefined"!=typeof c?("undefined"!=typeof b&&b.exports&&(c=b.exports=e),c.THREE=e):this.THREE=e},{}],13:[function(a,b,c){void 0===Date.now&&(Date.now=function(){return(new Date).valueOf()});var d=d||function(){var a=[];return{REVISION:"13",getAll:function(){return a},removeAll:function(){a=[]},add:function(b){a.push(b)},remove:function(b){var c=a.indexOf(b);-1!==c&&a.splice(c,1)},update:function(b){if(0===a.length)return!1;var c=0;for(b=void 0!==b?b:"undefined"!=typeof window&&void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now();ca;a++)p[a].stop()},this.delay=function(a){return l=a,this},this.repeat=function(a){return h=a,this},this.yoyo=function(a){return i=a,this},this.easing=function(a){return n=a,this},this.interpolation=function(a){return o=a,this},this.chain=function(){return p=arguments,this},this.onStart=function(a){return q=a,this},this.onUpdate=function(a){return s=a,this},this.onComplete=function(a){return t=a,this},this.onStop=function(a){return u=a,this},this.update=function(a){var d;if(m>a)return!0;r===!1&&(null!==q&&q.call(b),r=!0);var j=(a-m)/g;j=j>1?1:j;var u=n(j);for(d in e){var v=c[d]||0,w=e[d];w instanceof Array?b[d]=o(w,u):("string"==typeof w&&(w=v+parseFloat(w,10)),"number"==typeof w&&(b[d]=v+(w-v)*u))}if(null!==s&&s.call(b,u),1==j){if(h>0){isFinite(h)&&h--;for(d in f){if("string"==typeof e[d]&&(f[d]=f[d]+parseFloat(e[d],10)),i){var x=f[d];f[d]=e[d],e[d]=x}c[d]=f[d]}return i&&(k=!k),m=a+l,!0}null!==t&&t.call(b);for(var y=0,z=p.length;z>y;y++)p[y].start(a);return!1}return!0}},d.Easing={Linear:{None:function(a){return a}},Quadratic:{In:function(a){return a*a},Out:function(a){return a*(2-a)},InOut:function(a){return(a*=2)<1?.5*a*a:-.5*(--a*(a-2)-1)}},Cubic:{In:function(a){return a*a*a},Out:function(a){return--a*a*a+1},InOut:function(a){return(a*=2)<1?.5*a*a*a:.5*((a-=2)*a*a+2)}},Quartic:{In:function(a){return a*a*a*a},Out:function(a){return 1- --a*a*a*a},InOut:function(a){return(a*=2)<1?.5*a*a*a*a:-.5*((a-=2)*a*a*a-2)}},Quintic:{In:function(a){return a*a*a*a*a},Out:function(a){return--a*a*a*a*a+1},InOut:function(a){return(a*=2)<1?.5*a*a*a*a*a:.5*((a-=2)*a*a*a*a+2)}},Sinusoidal:{In:function(a){return 1-Math.cos(a*Math.PI/2)},Out:function(a){return Math.sin(a*Math.PI/2)},InOut:function(a){return.5*(1-Math.cos(Math.PI*a))}},Exponential:{In:function(a){return 0===a?0:Math.pow(1024,a-1)},Out:function(a){return 1===a?1:1-Math.pow(2,-10*a)},InOut:function(a){return 0===a?0:1===a?1:(a*=2)<1?.5*Math.pow(1024,a-1):.5*(-Math.pow(2,-10*(a-1))+2)}},Circular:{In:function(a){return 1-Math.sqrt(1-a*a)},Out:function(a){return Math.sqrt(1- --a*a)},InOut:function(a){return(a*=2)<1?-.5*(Math.sqrt(1-a*a)-1):.5*(Math.sqrt(1-(a-=2)*a)+1)}},Elastic:{In:function(a){var b,c=.1,d=.4;return 0===a?0:1===a?1:(!c||1>c?(c=1,b=d/4):b=d*Math.asin(1/c)/(2*Math.PI),-(c*Math.pow(2,10*(a-=1))*Math.sin((a-b)*(2*Math.PI)/d)))},Out:function(a){var b,c=.1,d=.4;return 0===a?0:1===a?1:(!c||1>c?(c=1,b=d/4):b=d*Math.asin(1/c)/(2*Math.PI),c*Math.pow(2,-10*a)*Math.sin((a-b)*(2*Math.PI)/d)+1)},InOut:function(a){var b,c=.1,d=.4;return 0===a?0:1===a?1:(!c||1>c?(c=1,b=d/4):b=d*Math.asin(1/c)/(2*Math.PI),(a*=2)<1?-.5*(c*Math.pow(2,10*(a-=1))*Math.sin((a-b)*(2*Math.PI)/d)):c*Math.pow(2,-10*(a-=1))*Math.sin((a-b)*(2*Math.PI)/d)*.5+1)}},Back:{In:function(a){var b=1.70158;return a*a*((b+1)*a-b)},Out:function(a){var b=1.70158;return--a*a*((b+1)*a+b)+1},InOut:function(a){var b=2.5949095;return(a*=2)<1?.5*(a*a*((b+1)*a-b)):.5*((a-=2)*a*((b+1)*a+b)+2)}},Bounce:{In:function(a){return 1-d.Easing.Bounce.Out(1-a)},Out:function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375},InOut:function(a){return.5>a?.5*d.Easing.Bounce.In(2*a):.5*d.Easing.Bounce.Out(2*a-1)+.5}}},d.Interpolation={Linear:function(a,b){var c=a.length-1,e=c*b,f=Math.floor(e),g=d.Interpolation.Utils.Linear;return 0>b?g(a[0],a[1],e):b>1?g(a[c],a[c-1],c-e):g(a[f],a[f+1>c?c:f+1],e-f)},Bezier:function(a,b){var c,e=0,f=a.length-1,g=Math.pow,h=d.Interpolation.Utils.Bernstein;for(c=0;f>=c;c++)e+=g(1-b,f-c)*g(b,c)*a[c]*h(f,c);return e},CatmullRom:function(a,b){var c=a.length-1,e=c*b,f=Math.floor(e),g=d.Interpolation.Utils.CatmullRom;return a[0]===a[c]?(0>b&&(f=Math.floor(e=c*(1+b))),g(a[(f-1+c)%c],a[f],a[(f+1)%c],a[(f+2)%c],e-f)):0>b?a[0]-(g(a[0],a[0],a[1],a[1],-e)-a[0]):b>1?a[c]-(g(a[c],a[c],a[c-1],a[c-1],e-c)-a[c]):g(a[f?f-1:0],a[f],a[f+1>c?c:f+1],a[f+2>c?c:f+2],e-f)},Utils:{Linear:function(a,b,c){return(b-a)*c+a},Bernstein:function(a,b){var c=d.Interpolation.Utils.Factorial;return c(a)/c(b)/c(a-b)},Factorial:function(){var a=[1];return function(b){var c,d=1;if(a[b])return a[b];for(c=b;c>1;c--)d*=c;return a[b]=d}}(),CatmullRom:function(a,b,c,d,e){var f=.5*(c-a),g=.5*(d-b),h=e*e,i=e*h;return(2*b-2*c+f+g)*i+(-3*b+3*c-2*f-g)*h+f*e+b}}},b.exports=d},{}],14:[function(a,b,c){!function d(a,c,e){function f(a,b){return this instanceof f?(g(a)?(b=a[1],a=a[0]):"object"==typeof a&&a&&(b=a.y,a=a.x),this.x=f.clean(a||0),void(this.y=f.clean(b||0))):new f(a,b)}var g=function(a){return"[object Array]"===Object.prototype.toString.call(a)};f.prototype={change:function(a){if("function"==typeof a)this.observers?this.observers.push(a):this.observers=[a];else if(this.observers&&this.observers.length)for(var b=this.observers.length-1;b>=0;b--)this.observers[b](this,a);return this},ignore:function(a){if(this.observers)if(a)for(var b=this.observers,c=b.length;c--;)b[c]===a&&b.splice(c,1);else this.observers=[];return this},set:function(a,b,c){if("number"!=typeof a&&(c=b,b=a.y,a=a.x),this.x===a&&this.y===b)return this;var d=null;return c!==!1&&this.observers&&this.observers.length&&(d=this.clone()),this.x=f.clean(a),this.y=f.clean(b),c!==!1?this.change(d):void 0; -},zero:function(){return this.set(0,0)},clone:function(){return new this.constructor(this.x,this.y)},negate:function(a){return a?new this.constructor(-this.x,-this.y):this.set(-this.x,-this.y)},add:function(a,b,c){return"number"!=typeof a&&(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)),a+=this.x,b+=this.y,c?new this.constructor(a,b):this.set(a,b)},subtract:function(a,b,c){return"number"!=typeof a&&(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)),a=this.x-a,b=this.y-b,c?new this.constructor(a,b):this.set(a,b)},multiply:function(a,b,c){return"number"!=typeof a?(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)):"number"!=typeof b&&(c=b,b=a),a*=this.x,b*=this.y,c?new this.constructor(a,b):this.set(a,b)},rotate:function(a,b,c){var d,e,f=this.x,g=this.y,h=Math.cos(a),i=Math.sin(a);return b=b?-1:1,d=h*f-b*i*g,e=b*i*f+h*g,c?new this.constructor(d,e):this.set(d,e)},length:function(){var a=this.x,b=this.y;return Math.sqrt(a*a+b*b)},lengthSquared:function(){var a=this.x,b=this.y;return a*a+b*b},distance:function(a){var b=this.x-a.x,c=this.y-a.y;return Math.sqrt(b*b+c*c)},normalize:function(a){var b=this.length(),c=bc?c:e,h=f>d?d:f;return b?new this.constructor(g,h):this.set(g,h)},max:function(a,b){var c=this.x,d=this.y,e=a.x,f=a.y,g=c>e?c:e,h=d>f?d:f;return b?new this.constructor(g,h):this.set(g,h)},clamp:function(a,b,c){var d=this.min(b,!0).max(a);return c?d:this.set(d.x,d.y)},lerp:function(a,b,c){return this.add(a.subtract(this,!0).multiply(b),c)},skew:function(a){return a?new this.constructor(-this.y,this.x):this.set(-this.y,this.x)},dot:function(a){return f.clean(this.x*a.x+a.y*this.y)},perpDot:function(a){return f.clean(this.x*a.y-this.y*a.x)},angleTo:function(a){return Math.atan2(this.perpDot(a),this.dot(a))},divide:function(a,b,c){if("number"!=typeof a?(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)):"number"!=typeof b&&(c=b,b=a),0===a||0===b)throw new Error("division by zero");if(isNaN(a)||isNaN(b))throw new Error("NaN detected");return c?new this.constructor(this.x/a,this.y/b):this.set(this.x/a,this.y/b)},isPointOnLine:function(a,b){return(a.y-this.y)*(a.x-b.x)===(a.y-b.y)*(a.x-this.x)},toArray:function(){return[this.x,this.y]},fromArray:function(a){return this.set(a[0],a[1])},toJSON:function(){return{x:this.x,y:this.y}},toString:function(){return"("+this.x+", "+this.y+")"},constructor:f},f.fromArray=function(a,b){return new(b||f)(a[0],a[1])},f.precision=c||8;var h=Math.pow(10,f.precision);return f.clean=a||function(a){if(isNaN(a))throw new Error("NaN detected");if(!isFinite(a))throw new Error("Infinity detected");return Math.round(a)===a?a:Math.round(a*h)/h},f.inject=d,a||(f.fast=d(function(a){return a}),"undefined"!=typeof b&&"object"==typeof b.exports?b.exports=f:window.Vec2=window.Vec2||f),f}()},{}],15:[function(a,b,c){function d(a,b,c){c||(c={}),this.width=a,this.height=b,this.points=[],this.introLines=new f.Object3D,this.pins=[],this.markers=[],this.satelliteAnimations=[],this.satelliteMeshes=[],this.satellites={},this.quadtree=new g(new h(180,360),5),this.active=!0;var d={font:"Inconsolata",baseColor:"#ffcc00",markerColor:"#ffcc00",pinColor:"#00eeee",satelliteColor:"#ff0000",introLinesAltitude:1.1,introLinesDuration:2e3,introLinesColor:"#8FD8D8",introLinesCount:60,scale:1,dayLength:28e3,maxPins:500,maxMarkers:4,data:[],tiles:[],viewAngle:.1,cameraAngle:Math.PI};for(var e in d)this[e]||(this[e]=d[e],void 0!==c[e]&&(this[e]=c[e]));0===this.dayLength?this.rotationSpeed=0:this.rotationSpeed=1e3/this.dayLength,this.setScale(this.scale),this.renderer=new f.WebGLRenderer({antialias:!0}),this.renderer.setSize(this.width,this.height),this.renderer.gammaInput=!0,this.renderer.gammaOutput=!0,this.domElement=this.renderer.domElement,this.data.sort(function(a,b){return b.lng-2*b.label.length-(a.lng-2*a.label.length)});for(var e=0;e0&&this.firstRunTime+(next=this.data.pop()).when=Date.now()&&this.data.push(next)}},q=function(){this.hexGrid&&this.scene.remove(this.hexGrid);var a=["#define PI 3.141592653589793238462643","#define DISTANCE 500.0","#define INTRODURATION "+(parseFloat(this.introLinesDuration)+1e-5),"#define INTROALTITUDE "+(parseFloat(this.introLinesAltitude)+1e-5),"attribute float lng;","uniform float currentTime;","varying vec4 vColor;","","void main()","{"," vec3 newPos = position;"," float opacityVal = 0.0;"," float introStart = INTRODURATION * ((180.0 + lng)/360.0);"," if(currentTime > introStart){"," opacityVal = 1.0;"," }"," if(currentTime > introStart && currentTime < introStart + INTRODURATION / 8.0){"," newPos = position * INTROALTITUDE;"," opacityVal = .3;"," }"," if(currentTime > introStart + INTRODURATION / 8.0 && currentTime < introStart + INTRODURATION / 8.0 + 200.0){"," newPos = position * (1.0 + ((INTROALTITUDE-1.0) * (1.0-(currentTime - introStart-(INTRODURATION/8.0))/200.0)));"," }"," vColor = vec4( color, opacityVal );"," gl_Position = projectionMatrix * modelViewMatrix * vec4(newPos, 1.0);","}"].join("\n"),b=["varying vec4 vColor;","void main()","{"," gl_FragColor = vColor;"," float depth = gl_FragCoord.z / gl_FragCoord.w;"," float fogFactor = smoothstep("+parseInt(this.cameraDistance)+".0,"+parseInt(this.cameraDistance+300)+".0, depth );"," vec3 fogColor = vec3(0.0);"," gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w ), fogFactor );","}"].join("\n"),c={lng:{type:"f",value:null}};this.pointUniforms={currentTime:{type:"f",value:0}};var d=new f.ShaderMaterial({uniforms:this.pointUniforms,attributes:c,vertexShader:a,fragmentShader:b,transparent:!0,vertexColors:f.VertexColors,side:f.DoubleSide}),e=4*this.tiles.length,g=new f.BufferGeometry;g.addAttribute("index",Uint16Array,3*e,1),g.addAttribute("position",Float32Array,3*e,3),g.addAttribute("normal",Float32Array,3*e,3),g.addAttribute("color",Float32Array,3*e,3),g.addAttribute("lng",Float32Array,3*e,1);for(var h=g.attributes.lng.array,i=m(this.baseColor).hueSet(),j=[],k=0;k5&&q(s+3,r.b[0].x,r.b[0].y,r.b[0].z,r.b[5].x,r.b[5].y,r.b[5].z,r.b[4].x,r.b[4].y,r.b[4].z,r.lat,r.lon,v)}g.offsets=[];for(var w=e/l,k=0;w>k;k++){var x={start:k*l*3,index:k*l*3,count:3*Math.min(e-k*l,l)};g.offsets.push(x)}g.computeBoundingSphere(),this.hexGrid=new f.Mesh(g,d),this.scene.add(this.hexGrid)},r=function(){for(var a,b=new f.LineBasicMaterial({color:this.introLinesColor,transparent:!0,linewidth:2,opacity:.5}),c=0;ci;i++){var j=n.mapPoint(e,g-5*i);a=new f.Vector3(j.x*this.introLinesAltitude,j.y*this.introLinesAltitude,j.z*this.introLinesAltitude),d.vertices.push(a)}this.introLines.add(new f.Line(d,b))}this.scene.add(this.introLines)},s=function(a){var b,c=!1,d=0,e=Date.now(),g=!1,h=new f.Vector3(0,0,0),i=new f.Projector;a.domElement.onmousedown=function(a){c=!0,d=a.clientX,e=Date.now(),g=!1},a.domElement.onmouseup=function(b){c=!1,a.resetRotationSpeed()},a.domElement.onmouseleave=function(b){c=!1,a.resetRotationSpeed()};var j=function(f,i){h.x=2*(f.clientX/a.width)-1,h.y=1-2*(f.clientY/a.height);var k=Date.now()-e;c&&k&&(g=!0,a.setRotationSpeed((f.clientX-d)/a.width/(k/1e3)),e=Date.now(),d=f.clientX,clearTimeout(b),i||(b=setTimeout(function(){j(f,!0)},100)))},k=function(b){if(!g){for(var c=i.pickingRay(h.clone(),a.camera),d=c.intersectObjects(a.scene.children),e=1.1*a.cameraDistance,f=null,j=0;j0)){var k=a.camera.position.distanceTo(d[j].object.position);e>k&&(e=k,f=objName)}null!=f&&a.clickHandler&&a.clickHandler(f)}};a.domElement.onmousemove=j,a.domElement.onclick=k};d.prototype.init=function(a){this.camera=new f.PerspectiveCamera(50,this.width/this.height,1,this.cameraDistance+300),this.camera.position.z=this.cameraDistance,this.scene=new f.Scene,this.scene.fog=new f.Fog(0,this.cameraDistance,this.cameraDistance+300),r.call(this),this.smokeProvider=new l(this.scene),q.call(this),setTimeout(a,500)},d.prototype.destroy=function(a){var b=this;this.active=!1,setTimeout(function(){for(;b.scene.children.length>0;)b.scene.remove(b.scene.children[0]);"function"==typeof a&&a()},1e3)},d.prototype.addPin=function(a,b,c,d){a=parseFloat(a),b=parseFloat(b);var e={lineColor:this.pinColor,topColor:this.pinColor,font:this.font,id:d},f=1.2;"string"==typeof c&&0!==c.length||(f-=.05+.05*Math.random());var g=new i(a,b,c,f,this.scene,this.smokeProvider,e);this.pins.push(g);var j=o(a,b);if(g.pos_=new h(parseInt(j.x),parseInt(j.y)),c.length>0?g.rad_=j.rad:g.rad_=1,this.quadtree.addObject(g),c.length>0){var k=this.quadtree.getCollisionsForObject(g),l=0,m=0,n=[];for(var p in k)k[p].text.length>0&&(l++,k[p].age()>5e3?n.push(k[p]):m++);if(l>0&&0==m)for(var p=0;p0&&(g.hideLabel(),g.hideSmoke(),g.hideTop(),g.changeAltitude(.05*Math.random()+1.1))}if(this.pins.length>this.maxPins){var q=this.pins.shift();this.quadtree.removeObject(q),q.remove()}return g},d.prototype.addMarker=function(a,b,c,d){var e,f={markerColor:this.markerColor,lineColor:this.markerColor,font:this.font};return e="boolean"==typeof d&&d?new j(a,b,c,1.2,this.markers[this.markers.length-1],this.scene,f):"object"==typeof d?new j(a,b,c,1.2,d,this.scene,f):new j(a,b,c,1.2,null,this.scene,f),this.markers.push(e),this.markers.length>this.maxMarkers&&this.markers.shift().remove(),e},d.prototype.addSatellite=function(a,b,c,d,e,f){d||(d={}),void 0==d.coreColor&&(d.coreColor=this.satelliteColor);var g=new k(a,b,c,this.scene,d,e,f);return this.satellites[g.toString()]||(this.satellites[g.toString()]=g),g.onRemove(function(){delete this.satellites[g.toString()]}.bind(this)),g},d.prototype.addConstellation=function(a,b){for(var c,d=[],e=0;ethis.maxPins;){var b=this.pins.shift();this.quadtree.removeObject(b),b.remove()}},d.prototype.setMaxMarkers=function(a){for(this.maxMarkers=a;this.markers.length>this.maxMarkers;)this.markers.shift().remove()},d.prototype.setBaseColor=function(a){this.baseColor=a,q.call(this)},d.prototype.setMarkerColor=function(a){this.markerColor=a,this.scene._encom_markerTexture=null},d.prototype.setPinColor=function(a){this.pinColor=a},d.prototype.setScale=function(a){this.scale=a,this.cameraDistance=1700/a,this.scene&&this.scene.fog&&(this.scene.fog.near=this.cameraDistance,this.scene.fog.far=this.cameraDistance+300,q.call(this),this.camera.far=this.cameraDistance+300,this.camera.updateProjectionMatrix())},d.prototype.setRotationSpeed=function(a){this.rotationSpeed=a},d.prototype.resetRotationSpeed=function(){this.rotationSpeed=this.defaultRotationSpeed},d.prototype.tick=function(){if(this.camera){this.firstRunTime||(this.firstRunTime=Date.now()),p.call(this),e.update(),this.lastRenderDate||(this.lastRenderDate=new Date),this.firstRenderDate||(this.firstRenderDate=new Date),this.totalRunTime=new Date-this.firstRenderDate;var a=new Date-this.lastRenderDate;this.lastRenderDate=new Date;var b=this.rotationSpeed*a/1e3*2*Math.PI;this.cameraAngle+=b,this.active||(this.cameraDistance+=1e3*a/1e3),this.camera.position.x=this.cameraDistance*Math.cos(this.cameraAngle)*Math.cos(this.viewAngle),this.camera.position.y=Math.sin(this.viewAngle)*this.cameraDistance,this.camera.position.z=this.cameraDistance*Math.sin(this.cameraAngle)*Math.cos(this.viewAngle);for(var c in this.satellites)this.satellites[c].tick(this.camera.position,this.cameraAngle,a);for(var c=0;cthis.totalRunTime?(this.totalRunTime/this.introLinesDuration<.1&&(this.introLines.children[0].material.opacity=this.totalRunTime/this.introLinesDuration*10-.2),this.totalRunTime/this.introLinesDuration>.8?this.introLines.children[0].material.opacity=5*Math.max(1-this.totalRunTime/this.introLinesDuration,0):this.introLines.children[0].material.opacity=1,this.introLines.rotateY(2*Math.PI/(this.introLinesDuration/a))):this.introLines&&(this.scene.remove(this.introLines),delete[this.introLines]),this.pointUniforms.currentTime.value=this.totalRunTime,this.smokeProvider.tick(this.totalRunTime),this.camera.lookAt(this.scene.position),this.renderer.render(this.scene,this.camera)}},d.prototype.setClickHandler=function(a){this.clickHandler=a},b.exports=d},{"./Marker":16,"./Pin":17,"./Satellite":18,"./SmokeProvider":19,"./utils":21,"hexasphere.js":3,"pusher.color":6,quadtree2:8,three:12,"tween.js":13,vec2:14}],16:[function(a,b,c){var d=a("three"),e=a("tween.js"),f=a("./utils"),g=function(a){var b,c,e=30,g=30;return b=f.renderToCanvas(e,g,function(b){b.fillStyle=a,b.strokeStyle=a,b.lineWidth=3,b.beginPath(),b.arc(e/2,g/2,e/3,0,2*Math.PI),b.stroke(),b.beginPath(),b.arc(e/2,g/2,e/5,0,2*Math.PI),b.fill()}),c=new d.Texture(b),c.needsUpdate=!0,c},h=function(a,b,c,h,i,j,k){var l,m,n,o,p,q,r={lineColor:"#FFCC00",lineWidth:1,markerColor:"#FFCC00",labelColor:"#FFF",font:"Inconsolata",fontSize:20,drawTime:2e3,lineSegments:150};if(this.lat=parseFloat(a),this.lon=parseFloat(b),this.text=c,this.altitude=parseFloat(h),this.scene=j,this.previous=i,this.next=[],this.previous&&this.previous.next.push(this),k)for(var s in r)void 0!=k[s]&&(r[s]=k[s]);this.opts=r,l=f.mapPoint(a,b),i&&(m=f.mapPoint(i.lat,i.lon)),j._encom_markerTexture||(j._encom_markerTexture=g(this.opts.markerColor)),n=new d.SpriteMaterial({map:j._encom_markerTexture,opacity:.7,depthTest:!0,fog:!0}),this.marker=new d.Sprite(n),this.marker.scale.set(0,0),this.marker.position.set(l.x*h,l.y*h,l.z*h),o=f.createLabel(c.toUpperCase(),this.opts.fontSize,this.opts.labelColor,this.opts.font,this.opts.markerColor),p=new d.Texture(o),p.needsUpdate=!0,q=new d.SpriteMaterial({map:p,useScreenCoordinates:!1,opacity:0,depthTest:!0,fog:!0}),this.labelSprite=new d.Sprite(q),this.labelSprite.position={x:l.x*h*1.1,y:l.y*h*1.05+(l.y<0?-15:30),z:l.z*h*1.1},this.labelSprite.scale.set(o.width,o.height),new e.Tween({opacity:0}).to({opacity:1},500).onUpdate(function(){q.opacity=this.opacity}).start();var t=this;if(new e.Tween({x:0,y:0}).to({x:50,y:50},2e3).easing(e.Easing.Elastic.Out).onUpdate(function(){t.marker.scale.set(this.x,this.y)}).delay(this.previous?t.opts.drawTime:0).start(),this.previous){var u,v,w,x,y,z,A,B,C,D,E,F,G=[],H=[];t.geometrySpline=new d.Geometry,u=new d.LineBasicMaterial({color:this.opts.lineColor,transparent:!0,linewidth:3,opacity:.5}),t.geometrySplineDotted=new d.Geometry,v=new d.LineBasicMaterial({color:this.opts.lineColor,linewidth:1,transparent:!0,opacity:.5}),w=(a-i.lat)/t.opts.lineSegments,x=(b-i.lon)/t.opts.lineSegments,y=f.mapPoint(i.lat,i.lon),G=[],H=[];for(var I=0;I=a.index&&(E.set(1.2*D.x,1.2*D.y,1.2*D.z),currentVert2.set(1.19*currentPoint2.x,1.19*currentPoint2.y,1.19*currentPoint2.z)),t.geometrySpline.verticesNeedUpdate=!0,t.geometrySplineDotted.verticesNeedUpdate=!0;G.length>0&&setTimeout(F,t.opts.drawTime/t.opts.lineSegments)},F(),this.scene.add(new d.Line(t.geometrySpline,u)),this.scene.add(new d.Line(t.geometrySplineDotted,v,d.LinePieces))}this.scene.add(this.marker),this.scene.add(this.labelSprite)};h.prototype.remove=function(){for(var a=0,b=this,c=function(d){for(var e=0;a>e;e++)d.geometrySpline.vertices[e].set(d.geometrySpline.vertices[e+1]),d.geometrySplineDotted.vertices[e].set(d.geometrySplineDotted.vertices[e+1]),d.geometrySpline.verticesNeedUpdate=!0,d.geometrySplineDotted.verticesNeedUpdate=!0;a++,a0,showTop:c.length>0,showSmoke:c.length>0,id:null};if(this.lat=a,this.lon=b,this.text=c,this.altitude=h,this.scene=i,this.smokeProvider=j,this.dateCreated=Date.now(),k)for(var t in s)void 0!=k[t]&&(s[t]=k[t]);this.opts=s,this.topVisible=s.showTop,this.smokeVisible=s.showSmoke,this.labelVisible=s.showLabel,this.lineGeometry=new d.Geometry,l=new d.LineBasicMaterial({color:s.lineColor,linewidth:s.lineWidth}),r=f.mapPoint(a,b),this.lineGeometry.vertices.push(new d.Vector3(r.x,r.y,r.z)),this.lineGeometry.vertices.push(new d.Vector3(r.x,r.y,r.z)),this.line=new d.Line(this.lineGeometry,l),m=f.createLabel(c,18,s.labelColor,s.font),n=new d.Texture(m),n.needsUpdate=!0,o=new d.SpriteMaterial({map:n,useScreenCoordinates:!1,opacity:0,depthTest:!0,fog:!0}),this.labelSprite=new d.Sprite(o),this.labelSprite.position={x:r.x*h*1.1,y:r.y*h+(r.y<0?-15:30),z:r.z*h*1.1},this.labelSprite.scale.set(m.width,m.height),p=new d.Texture(g(s.topColor)),p.needsUpdate=!0,q=new d.SpriteMaterial({map:p,depthTest:!0,fog:!0,opacity:0}),this.topSprite=new d.Sprite(q),this.topSprite.scale.set(20,20),this.topSprite.position.set(r.x*h,r.y*h,r.z*h),this.smokeVisible&&(this.smokeId=j.setFire(a,b,h));var u=this;(s.showTop||s.showLabel)&&new e.Tween({opacity:0}).to({opacity:1},500).onUpdate(function(){u.topVisible?q.opacity=this.opacity:q.opacity=0,u.labelVisible?o.opacity=this.opacity:o.opacity=0}).delay(1e3).start(),new e.Tween(r).to({x:r.x*h,y:r.y*h,z:r.z*h},1500).easing(e.Easing.Elastic.Out).onUpdate(function(){u.lineGeometry.vertices[1].x=this.x,u.lineGeometry.vertices[1].y=this.y,u.lineGeometry.vertices[1].z=this.z,u.lineGeometry.verticesNeedUpdate=!0}).start(),null!==this.opts.id&&void 0!==this.opts.id&&(this.labelSprite.name=this.opts.id,this.line.name=this.opts.id,this.topSprite.name=this.opts.id),this.scene.add(this.labelSprite),this.scene.add(this.line),this.scene.add(this.topSprite)};h.prototype.toString=function(){return""+this.lat+"_"+this.lon},h.prototype.changeAltitude=function(a){var b=f.mapPoint(this.lat,this.lon),c=this;new e.Tween({altitude:this.altitude}).to({altitude:a},1500).easing(e.Easing.Elastic.Out).onUpdate(function(){c.smokeVisible&&c.smokeProvider.changeAltitude(this.altitude,c.smokeId),c.topVisible&&c.topSprite.position.set(b.x*this.altitude,b.y*this.altitude,b.z*this.altitude),c.labelVisible&&(c.labelSprite.position={x:b.x*this.altitude*1.1,y:b.y*this.altitude+(b.y<0?-15:30),z:b.z*this.altitude*1.1}),c.lineGeometry.vertices[1].x=b.x*this.altitude,c.lineGeometry.vertices[1].y=b.y*this.altitude,c.lineGeometry.vertices[1].z=b.z*this.altitude,c.lineGeometry.verticesNeedUpdate=!0}).onComplete(function(){c.altitude=a}).start()},h.prototype.hideTop=function(){this.topVisible&&(this.topSprite.material.opacity=0,this.topVisible=!1)},h.prototype.showTop=function(){this.topVisible||(this.topSprite.material.opacity=1,this.topVisible=!0)},h.prototype.hideLabel=function(){this.labelVisible&&(this.labelSprite.material.opacity=0,this.labelVisible=!1)},h.prototype.showLabel=function(){this.labelVisible||(this.labelSprite.material.opacity=1,this.labelVisible=!0)},h.prototype.hideSmoke=function(){this.smokeVisible&&(this.smokeProvider.extinguish(this.smokeId),this.smokeVisible=!1)},h.prototype.showSmoke=function(){this.smokeVisible||(this.smokeId=this.smokeProvider.setFire(this.lat,this.lon,this.altitude),this.smokeVisible=!0)},h.prototype.age=function(){return Date.now()-this.dateCreated},h.prototype.remove=function(){this.scene.remove(this.labelSprite),this.scene.remove(this.line),this.scene.remove(this.topSprite),this.smokeVisible&&this.smokeProvider.extinguish(this.smokeId)},b.exports=h},{"./utils":21,three:12,"tween.js":13}],18:[function(a,b,c){var d=a("./TextureAnimator"),e=a("three"),f=a("./utils"),g=function(a,b,c,d,e,g,h,i){var j=a/c,k=Math.floor((a-d)/e),l=b-25,m=l/(a-d),n=0,o=0,p=0,q=f.hexToRgb(g);return f.renderToCanvas(a*b/c,b*c,function(c){for(var f=0;a>f;f++){f-p*j>=j&&(n=0,o+=b,p++);var g=n+25,l=o+Math.floor(b/2);c.lineWidth=2,c.strokeStyle=i;var r=Math.PI/16,s=-Math.PI+Math.PI/4,t=8,u=Math.floor(a-2*(a-d)/e)+1;d>f&&(t=t*f/d);for(var v=Math.floor((u-d)/2)+d,w=0;4>w;w++){if(c.beginPath(),d>f||f>=a)c.arc(g,l,t,w*Math.PI/2+s+r,w*Math.PI/2+s+Math.PI/2-2*r);else if(f>d&&v>f){var x=v-d,y=3*Math.PI/2,z=f-d,A=y/x,B=-Math.PI+Math.PI/4+r+A*z;c.arc(g,l,t,Math.max(w*Math.PI/2+s,B),Math.max(w*Math.PI/2+s+Math.PI/2-2*r,B+Math.PI/2-2*r))}else if(f>=v&&u>f){var x=u-v,y=2*w*Math.PI/4,z=f-v,A=y/x,B=Math.PI/2+Math.PI/4+r+A*z;c.arc(g,l,t,B,B+Math.PI/2-2*r)}else if(f>=u&&(a-u)/2+u>f){var x=(a-u)/2,y=Math.PI/2,z=f-u,A=y/x,B=w*(Math.PI/2)+Math.PI/4+r+A*z;c.arc(g,l,t,B,B+Math.PI/2-2*r)}else c.arc(g,l,t,w*Math.PI/2+s+r,w*Math.PI/2+s+Math.PI/2-2*r);c.stroke()}for(var C,D=0;e>D;D++)C=f-k*D-d,C>0&&b-25>C*m&&(c.strokeStyle="rgba("+q.r+","+q.g+","+q.b+","+(.9-C*m/(b-25))+")",c.lineWidth=2,c.beginPath(),c.arc(g,l,C*m,-Math.PI/12,Math.PI/12),c.stroke());c.fillStyle="#000",c.beginPath(),c.arc(g,l,3,0,2*Math.PI),c.fill(),c.strokeStyle=h,c.lineWidth=2,c.beginPath(),d>f?c.arc(g,l,3*f/d,0,2*Math.PI):c.arc(g,l,3,0,2*Math.PI),c.stroke(),n+=b}})},h=function(a,b,c,h,i,j,k){var l,m,n,o,p,q,r,s=f.mapPoint(a,b);s.x*=c,s.y*=c,s.z*=c;var m={numWaves:8,waveColor:"#FFF",coreColor:"#FF0000",shieldColor:"#FFF",size:1};if(this.lat=a,this.lon=b,this.altitude=c,this.scene=h,this.onRemoveList=[],n=50,o=100,p=10,q=Math.floor(n/8),i)for(var t in m)void 0!=i[t]&&(m[t]=i[t]);this.opts=m,j?(this.canvas=j,k?this.texture=k:(this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,r=Math.floor(n-2*(n-q)/m.numWaves)+1,this.animator=new d(this.texture,p,n/p,n,80,r))):(this.canvas=g(n,o,p,q,m.numWaves,m.waveColor,m.coreColor,m.shieldColor),this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,r=Math.floor(n-2*(n-q)/m.numWaves)+1,this.animator=new d(this.texture,p,n/p,n,80,r)),l=new e.PlaneGeometry(150*m.size,150*m.size,1,1),this.material=new e.MeshBasicMaterial({map:this.texture,depthTest:!1,transparent:!0}),this.mesh=new e.Mesh(l,this.material),this.mesh.tiltMultiplier=Math.PI/2*(1-Math.abs(a/90)),this.mesh.tiltDirection=a>0?-1:1,this.mesh.lon=b,this.mesh.position.set(s.x,s.y,s.z),this.mesh.rotation.z=-1*(a/90)*Math.PI/2,this.mesh.rotation.y=b/180*Math.PI,h.add(this.mesh)};h.prototype.changeAltitude=function(a){var b=f.mapPoint(this.lat,this.lon);b.x*=a,b.y*=a,b.z*=a,this.altitude=a,this.mesh.position.set(b.x,b.y,b.z)},h.prototype.changeCanvas=function(a,b,c,f){numFrames=50,pixels=100,rows=10,waveStart=Math.floor(numFrames/8),a?this.opts.numWaves=a:a=this.opts.numWaves,b?this.opts.waveColor=b:b=this.opts.waveColor,c?this.opts.coreColor=c:c=this.opts.coreColor,f?this.opts.shieldColor=f:f=this.opts.shieldColor,this.canvas=g(numFrames,pixels,rows,waveStart,a,b,c,f),this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,repeatAt=Math.floor(numFrames-2*(numFrames-waveStart)/a)+1,this.animator=new d(this.texture,rows,numFrames/rows,numFrames,80,repeatAt),this.material.map=this.texture},h.prototype.tick=function(a,b,c){this.mesh.lookAt(a),this.mesh.rotateZ(this.mesh.tiltDirection*Math.PI/2),this.mesh.rotateZ(Math.sin(b+this.mesh.lon/180*Math.PI)*this.mesh.tiltMultiplier*this.mesh.tiltDirection*-1),this.animator&&this.animator.update(c)},h.prototype.remove=function(){this.scene.remove(this.mesh);for(var a=0;a 0.0 && active > 0.0) {"," dt = mod(dt,1500.0);"," }"," float opacity = 1.0 - dt/ 1500.0;"," if (dt == 0.0 || active == 0.0){"," opacity = 0.0;"," }"," vec3 newPos = getPos(myStartLat, myStartLon - ( dt / 50.0));"," vColor = vec4( color, opacity );"," vec4 mvPosition = modelViewMatrix * vec4( newPos, 1.0 );"," gl_PointSize = 2.5 - (dt / 1500.0);"," gl_Position = projectionMatrix * mvPosition;","}"].join("\n"),g=["varying vec4 vColor;","void main()","{"," gl_FragColor = vColor;"," float depth = gl_FragCoord.z / gl_FragCoord.w;"," float fogFactor = smoothstep(1500.0, 1800.0, depth );"," vec3 fogColor = vec3(0.0);"," gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w), fogFactor );","}"].join("\n"),h=function(a,b){var c={smokeCount:5e3,smokePerPin:30,smokePerSecond:20};if(b)for(var e in c)void 0!==b[e]&&(c[e]=b[e]);this.opts=c,this.geometry=new d.Geometry,this.attributes={myStartTime:{type:"f",value:[]},myStartLat:{type:"f",value:[]},myStartLon:{type:"f",value:[]},altitude:{type:"f",value:[]},active:{type:"f",value:[]}},this.uniforms={currentTime:{type:"f",value:0},color:{type:"c",value:new d.Color("#aaa")}};for(var h=new d.ShaderMaterial({uniforms:this.uniforms,attributes:this.attributes,vertexShader:f,fragmentShader:g,transparent:!0}),e=0;ethis.tileDisplayDuration;)if(this.shutDownFlag&&this.currentTile>=e)this.done=!0,this.shutDownCb();else{this.currentDisplayTime-=this.tileDisplayDuration,this.currentTile++,this.currentTile!=e||this.shutDownFlag||(this.currentTile=g);var c=this.currentTile%this.tilesHorizontal;a.offset.x=c/this.tilesHorizontal;var d=Math.floor(this.currentTile/this.tilesHorizontal);a.offset.y=1-d/this.tilesVertical-1/this.tilesVertical}},this.shutDown=function(a){_this.shutDownFlag=!0,_this.shutDownCb=a}};b.exports=e},{three:12}],21:[function(a,b,c){var d={renderToCanvas:function(a,b,c){var d=document.createElement("canvas");return d.width=a,d.height=b,c(d.getContext("2d")),d},mapPoint:function(a,b,c){c||(c=500);var d=(90-a)*Math.PI/180,e=(180-b)*Math.PI/180,f=c*Math.sin(d)*Math.cos(e),g=c*Math.cos(d),h=c*Math.sin(d)*Math.sin(e); -return{x:f,y:g,z:h}},hexToRgb:function(a){var b=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;a=a.replace(b,function(a,b,c,d){return b+b+c+c+d+d});var c=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a);return c?{r:parseInt(c[1],16),g:parseInt(c[2],16),b:parseInt(c[3],16)}:null},createLabel:function(a,b,c,d,e){var f=document.createElement("canvas"),g=f.getContext("2d");g.font=b+"pt "+d;var h=g.measureText(a).width;return f.width=h,f.height=b+10,f.width%2&&f.width++,f.height%2&&f.height++,e&&(f.height+=30),g.font=b+"pt "+d,g.textAlign="center",g.textBaseline="middle",g.strokeStyle="black",g.miterLimit=2,g.lineJoin="circle",g.lineWidth=6,g.strokeText(a,f.width/2,f.height/2),g.lineWidth=2,g.fillStyle=c,g.fillText(a,f.width/2,f.height/2),e&&(g.strokeStyle=e,g.lineWidth=4,g.beginPath(),g.moveTo(0,f.height-10),g.lineTo(f.width-1,f.height-10),g.stroke()),f}};b.exports=d},{}]},{},[1]); \ No newline at end of file +},zero:function(){return this.set(0,0)},clone:function(){return new this.constructor(this.x,this.y)},negate:function(a){return a?new this.constructor(-this.x,-this.y):this.set(-this.x,-this.y)},add:function(a,b,c){return"number"!=typeof a&&(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)),a+=this.x,b+=this.y,c?new this.constructor(a,b):this.set(a,b)},subtract:function(a,b,c){return"number"!=typeof a&&(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)),a=this.x-a,b=this.y-b,c?new this.constructor(a,b):this.set(a,b)},multiply:function(a,b,c){return"number"!=typeof a?(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)):"number"!=typeof b&&(c=b,b=a),a*=this.x,b*=this.y,c?new this.constructor(a,b):this.set(a,b)},rotate:function(a,b,c){var d,e,f=this.x,g=this.y,h=Math.cos(a),i=Math.sin(a);return b=b?-1:1,d=h*f-b*i*g,e=b*i*f+h*g,c?new this.constructor(d,e):this.set(d,e)},length:function(){var a=this.x,b=this.y;return Math.sqrt(a*a+b*b)},lengthSquared:function(){var a=this.x,b=this.y;return a*a+b*b},distance:function(a){var b=this.x-a.x,c=this.y-a.y;return Math.sqrt(b*b+c*c)},normalize:function(a){var b=this.length(),c=bc?c:e,h=f>d?d:f;return b?new this.constructor(g,h):this.set(g,h)},max:function(a,b){var c=this.x,d=this.y,e=a.x,f=a.y,g=c>e?c:e,h=d>f?d:f;return b?new this.constructor(g,h):this.set(g,h)},clamp:function(a,b,c){var d=this.min(b,!0).max(a);return c?d:this.set(d.x,d.y)},lerp:function(a,b,c){return this.add(a.subtract(this,!0).multiply(b),c)},skew:function(a){return a?new this.constructor(-this.y,this.x):this.set(-this.y,this.x)},dot:function(a){return f.clean(this.x*a.x+a.y*this.y)},perpDot:function(a){return f.clean(this.x*a.y-this.y*a.x)},angleTo:function(a){return Math.atan2(this.perpDot(a),this.dot(a))},divide:function(a,b,c){if("number"!=typeof a?(c=b,g(a)?(b=a[1],a=a[0]):(b=a.y,a=a.x)):"number"!=typeof b&&(c=b,b=a),0===a||0===b)throw new Error("division by zero");if(isNaN(a)||isNaN(b))throw new Error("NaN detected");return c?new this.constructor(this.x/a,this.y/b):this.set(this.x/a,this.y/b)},isPointOnLine:function(a,b){return(a.y-this.y)*(a.x-b.x)===(a.y-b.y)*(a.x-this.x)},toArray:function(){return[this.x,this.y]},fromArray:function(a){return this.set(a[0],a[1])},toJSON:function(){return{x:this.x,y:this.y}},toString:function(){return"("+this.x+", "+this.y+")"},constructor:f},f.fromArray=function(a,b){return new(b||f)(a[0],a[1])},f.precision=c||8;var h=Math.pow(10,f.precision);return f.clean=a||function(a){if(isNaN(a))throw new Error("NaN detected");if(!isFinite(a))throw new Error("Infinity detected");return Math.round(a)===a?a:Math.round(a*h)/h},f.inject=d,a||(f.fast=d(function(a){return a}),"undefined"!=typeof b&&"object"==typeof b.exports?b.exports=f:window.Vec2=window.Vec2||f),f}()},{}],15:[function(a,b,c){function d(a,b,c){c||(c={}),this.width=a,this.height=b,this.points=[],this.introLines=new f.Object3D,this.pins=[],this.markers=[],this.satelliteAnimations=[],this.satelliteMeshes=[],this.satellites={},this.quadtree=new g(new h(180,360),5),this.active=!0;var d={font:"Inconsolata",baseColor:"#ffcc00",markerColor:"#ffcc00",pinColor:"#00eeee",satelliteColor:"#ff0000",introLinesAltitude:1.1,introLinesDuration:2e3,introLinesColor:"#8FD8D8",introLinesCount:60,scale:1,dayLength:28e3,maxPins:500,maxMarkers:4,data:[],tiles:[],viewAngle:.1,cameraAngle:Math.PI,viewAngleResetTime:3e4};for(var e in d)this[e]||(this[e]=d[e],void 0!==c[e]&&(this[e]=c[e]));0===this.dayLength?this.rotationSpeed=0:this.rotationSpeed=1e3/this.dayLength,this.verticalRotationSpeed=0,this.setScale(this.scale),this.renderer=new f.WebGLRenderer({antialias:!0}),this.renderer.setSize(this.width,this.height),this.renderer.gammaInput=!0,this.renderer.gammaOutput=!0,this.domElement=this.renderer.domElement,this.data.sort(function(a,b){return b.lng-2*b.label.length-(a.lng-2*a.label.length)});for(var e=0;e0&&this.firstRunTime+(next=this.data.pop()).when=Date.now()&&this.data.push(next)}},q=function(){this.hexGrid&&this.scene.remove(this.hexGrid);var a=["#define PI 3.141592653589793238462643","#define DISTANCE 500.0","#define INTRODURATION "+(parseFloat(this.introLinesDuration)+1e-5),"#define INTROALTITUDE "+(parseFloat(this.introLinesAltitude)+1e-5),"attribute float lng;","uniform float currentTime;","varying vec4 vColor;","","void main()","{"," vec3 newPos = position;"," float opacityVal = 0.0;"," float introStart = INTRODURATION * ((180.0 + lng)/360.0);"," if(currentTime > introStart){"," opacityVal = 1.0;"," }"," if(currentTime > introStart && currentTime < introStart + INTRODURATION / 8.0){"," newPos = position * INTROALTITUDE;"," opacityVal = .3;"," }"," if(currentTime > introStart + INTRODURATION / 8.0 && currentTime < introStart + INTRODURATION / 8.0 + 200.0){"," newPos = position * (1.0 + ((INTROALTITUDE-1.0) * (1.0-(currentTime - introStart-(INTRODURATION/8.0))/200.0)));"," }"," vColor = vec4( color, opacityVal );"," gl_Position = projectionMatrix * modelViewMatrix * vec4(newPos, 1.0);","}"].join("\n"),b=["varying vec4 vColor;","void main()","{"," gl_FragColor = vColor;"," float depth = gl_FragCoord.z / gl_FragCoord.w;"," float fogFactor = smoothstep("+parseInt(this.cameraDistance)+".0,"+parseInt(this.cameraDistance+300)+".0, depth );"," vec3 fogColor = vec3(0.0);"," gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w ), fogFactor );","}"].join("\n"),c={lng:{type:"f",value:null}};this.pointUniforms={currentTime:{type:"f",value:0}};var d=new f.ShaderMaterial({uniforms:this.pointUniforms,attributes:c,vertexShader:a,fragmentShader:b,transparent:!0,vertexColors:f.VertexColors,side:f.DoubleSide}),e=4*this.tiles.length,g=new f.BufferGeometry;g.addAttribute("index",Uint16Array,3*e,1),g.addAttribute("position",Float32Array,3*e,3),g.addAttribute("normal",Float32Array,3*e,3),g.addAttribute("color",Float32Array,3*e,3),g.addAttribute("lng",Float32Array,3*e,1);for(var h=g.attributes.lng.array,i=m(this.baseColor).hueSet(),j=[],k=0;k5&&q(s+3,r.b[0].x,r.b[0].y,r.b[0].z,r.b[5].x,r.b[5].y,r.b[5].z,r.b[4].x,r.b[4].y,r.b[4].z,r.lat,r.lon,v)}g.offsets=[];for(var w=e/l,k=0;w>k;k++){var x={start:k*l*3,index:k*l*3,count:3*Math.min(e-k*l,l)};g.offsets.push(x)}g.computeBoundingSphere(),this.hexGrid=new f.Mesh(g,d),this.scene.add(this.hexGrid)},r=function(){for(var a,b=new f.LineBasicMaterial({color:this.introLinesColor,transparent:!0,linewidth:2,opacity:.5}),c=0;ci;i++){var j=n.mapPoint(e,g-5*i);a=new f.Vector3(j.x*this.introLinesAltitude,j.y*this.introLinesAltitude,j.z*this.introLinesAltitude),d.vertices.push(a)}this.introLines.add(new f.Line(d,b))}this.scene.add(this.introLines)},s=function(a){var b,c,d=!1,g={x:0,y:0},h=Date.now(),i=new f.Vector3(0,0,0),j=new f.Projector,k=function(){d=!1,a.resetRotationSpeed(),clearTimeout(c),c=setTimeout(function(){new e.Tween({viewAngle:a.viewAngle}).easing(e.Easing.Quadratic.InOut).to({viewAngle:a.defaultViewAngle},1e3).onUpdate(function(){a.viewAngle=this.viewAngle}).start()},a.viewAngleResetTime)},l=function(a){clearTimeout(c),d=!0,g={x:a.clientX,y:a.clientY},h=Date.now(),movedSinceMouseDown=0},m=function(c,e){i.x=2*(c.clientX/a.width)-1,i.y=1-2*(c.clientY/a.height);var f=Date.now()-h;d&&f&&(movedSinceMouseDown+=Math.abs(c.clientX-g.x)+Math.abs(c.clientY-g.y),a.setRotationSpeed((c.clientX-g.x)/a.width/(f/1e3)),a.setVerticalRotationSpeed((c.clientY-g.y)/a.height/2/(f/1e3)),h=Date.now(),g={x:c.clientX,y:c.clientY},clearTimeout(b),e||(b=setTimeout(function(){m(c,!0)},100)))},n=function(b){if(movedSinceMouseDown<50){for(var c=j.pickingRay(i.clone(),a.camera),d=c.intersectObjects(a.scene.children),e=1.1*a.cameraDistance,f=null,g=0;g0)){var h=a.camera.position.distanceTo(d[g].object.position);e>h&&(e=h,f=objName)}null!=f&&a.clickHandler&&a.clickHandler(f)}};a.domElement.onmousedown=l,a.domElement.onmouseup=k,a.domElement.onmouseleave=k,a.domElement.onmousemove=m,a.domElement.onclick=n};d.prototype.init=function(a){this.camera=new f.PerspectiveCamera(50,this.width/this.height,1,this.cameraDistance+300),this.camera.position.z=this.cameraDistance,this.scene=new f.Scene,this.scene.fog=new f.Fog(0,this.cameraDistance,this.cameraDistance+300),r.call(this),this.smokeProvider=new l(this.scene),q.call(this),setTimeout(a,500)},d.prototype.destroy=function(a){var b=this;this.active=!1,setTimeout(function(){for(;b.scene.children.length>0;)b.scene.remove(b.scene.children[0]);"function"==typeof a&&a()},1e3)},d.prototype.addPin=function(a,b,c,d){a=parseFloat(a),b=parseFloat(b);var e={lineColor:this.pinColor,topColor:this.pinColor,font:this.font,id:d},f=1.2;"string"==typeof c&&0!==c.length||(f-=.05+.05*Math.random());var g=new i(a,b,c,f,this.scene,this.smokeProvider,e);this.pins.push(g);var j=o(a,b);if(g.pos_=new h(parseInt(j.x),parseInt(j.y)),c.length>0?g.rad_=j.rad:g.rad_=1,this.quadtree.addObject(g),c.length>0){var k=this.quadtree.getCollisionsForObject(g),l=0,m=0,n=[];for(var p in k)k[p].text.length>0&&(l++,k[p].age()>5e3?n.push(k[p]):m++);if(l>0&&0==m)for(var p=0;p0&&(g.hideLabel(),g.hideSmoke(),g.hideTop(),g.changeAltitude(.05*Math.random()+1.1))}if(this.pins.length>this.maxPins){var q=this.pins.shift();this.quadtree.removeObject(q),q.remove()}return g},d.prototype.addMarker=function(a,b,c,d){var e,f={markerColor:this.markerColor,lineColor:this.markerColor,font:this.font};return e="boolean"==typeof d&&d?new j(a,b,c,1.2,this.markers[this.markers.length-1],this.scene,f):"object"==typeof d?new j(a,b,c,1.2,d,this.scene,f):new j(a,b,c,1.2,null,this.scene,f),this.markers.push(e),this.markers.length>this.maxMarkers&&this.markers.shift().remove(),e},d.prototype.addSatellite=function(a,b,c,d,e,f){d||(d={}),void 0==d.coreColor&&(d.coreColor=this.satelliteColor);var g=new k(a,b,c,this.scene,d,e,f);return this.satellites[g.toString()]||(this.satellites[g.toString()]=g),g.onRemove(function(){delete this.satellites[g.toString()]}.bind(this)),g},d.prototype.addConstellation=function(a,b){for(var c,d=[],e=0;ethis.maxPins;){var b=this.pins.shift();this.quadtree.removeObject(b),b.remove()}},d.prototype.setMaxMarkers=function(a){for(this.maxMarkers=a;this.markers.length>this.maxMarkers;)this.markers.shift().remove()},d.prototype.setBaseColor=function(a){this.baseColor=a,q.call(this)},d.prototype.setMarkerColor=function(a){this.markerColor=a,this.scene._encom_markerTexture=null},d.prototype.setPinColor=function(a){this.pinColor=a},d.prototype.setScale=function(a){this.scale=a,this.cameraDistance=1700/a,this.scene&&this.scene.fog&&(this.scene.fog.near=this.cameraDistance,this.scene.fog.far=this.cameraDistance+300,q.call(this),this.camera.far=this.cameraDistance+300,this.camera.updateProjectionMatrix())},d.prototype.setRotationSpeed=function(a){this.rotationSpeed=a},d.prototype.setVerticalRotationSpeed=function(a){this.verticalRotationSpeed=a},d.prototype.resetRotationSpeed=function(){this.rotationSpeed=this.defaultRotationSpeed,this.verticalRotationSpeed=0},d.prototype.tick=function(){if(this.camera){this.firstRunTime||(this.firstRunTime=Date.now()),p.call(this),e.update(),this.lastRenderDate||(this.lastRenderDate=new Date),this.firstRenderDate||(this.firstRenderDate=new Date),this.totalRunTime=new Date-this.firstRenderDate;var a=new Date-this.lastRenderDate;this.lastRenderDate=new Date;var b=this.rotationSpeed*a/1e3*2*Math.PI,c=this.verticalRotationSpeed*a/1e3*2*Math.PI;this.cameraAngle+=b,this.viewAngle+=c,this.viewAngle=Math.min(Math.PI/2,this.viewAngle),this.viewAngle=Math.max(-Math.PI/2,this.viewAngle),this.active||(this.cameraDistance+=1e3*a/1e3),this.camera.position.x=this.cameraDistance*Math.cos(this.cameraAngle)*Math.cos(this.viewAngle),this.camera.position.y=Math.sin(this.viewAngle)*this.cameraDistance,this.camera.position.z=this.cameraDistance*Math.sin(this.cameraAngle)*Math.cos(this.viewAngle);for(var d in this.satellites)this.satellites[d].tick(this.camera.position,this.cameraAngle,a);for(var d=0;dthis.totalRunTime?(this.totalRunTime/this.introLinesDuration<.1&&(this.introLines.children[0].material.opacity=this.totalRunTime/this.introLinesDuration*10-.2),this.totalRunTime/this.introLinesDuration>.8?this.introLines.children[0].material.opacity=5*Math.max(1-this.totalRunTime/this.introLinesDuration,0):this.introLines.children[0].material.opacity=1,this.introLines.rotateY(2*Math.PI/(this.introLinesDuration/a))):this.introLines&&(this.scene.remove(this.introLines),delete[this.introLines]),this.pointUniforms.currentTime.value=this.totalRunTime,this.smokeProvider.tick(this.totalRunTime),this.camera.lookAt(this.scene.position),this.renderer.render(this.scene,this.camera)}},d.prototype.setClickHandler=function(a){this.clickHandler=a},b.exports=d},{"./Marker":16,"./Pin":17,"./Satellite":18,"./SmokeProvider":19,"./utils":21,"hexasphere.js":3,"pusher.color":6,quadtree2:8,three:12,"tween.js":13,vec2:14}],16:[function(a,b,c){var d=a("three"),e=a("tween.js"),f=a("./utils"),g=function(a){var b,c,e=30,g=30;return b=f.renderToCanvas(e,g,function(b){b.fillStyle=a,b.strokeStyle=a,b.lineWidth=3,b.beginPath(),b.arc(e/2,g/2,e/3,0,2*Math.PI),b.stroke(),b.beginPath(),b.arc(e/2,g/2,e/5,0,2*Math.PI),b.fill()}),c=new d.Texture(b),c.needsUpdate=!0,c},h=function(a,b,c,h,i,j,k){var l,m,n,o,p,q,r={lineColor:"#FFCC00",lineWidth:1,markerColor:"#FFCC00",labelColor:"#FFF",font:"Inconsolata",fontSize:20,drawTime:2e3,lineSegments:150};if(this.lat=parseFloat(a),this.lon=parseFloat(b),this.text=c,this.altitude=parseFloat(h),this.scene=j,this.previous=i,this.next=[],this.previous&&this.previous.next.push(this),k)for(var s in r)void 0!=k[s]&&(r[s]=k[s]);this.opts=r,l=f.mapPoint(a,b),i&&(m=f.mapPoint(i.lat,i.lon)),j._encom_markerTexture||(j._encom_markerTexture=g(this.opts.markerColor)),n=new d.SpriteMaterial({map:j._encom_markerTexture,opacity:.7,depthTest:!0,fog:!0}),this.marker=new d.Sprite(n),this.marker.scale.set(0,0),this.marker.position.set(l.x*h,l.y*h,l.z*h),o=f.createLabel(c.toUpperCase(),this.opts.fontSize,this.opts.labelColor,this.opts.font,this.opts.markerColor),p=new d.Texture(o),p.needsUpdate=!0,q=new d.SpriteMaterial({map:p,useScreenCoordinates:!1,opacity:0,depthTest:!0,fog:!0}),this.labelSprite=new d.Sprite(q),this.labelSprite.position={x:l.x*h*1.1,y:l.y*h*1.05+(l.y<0?-15:30),z:l.z*h*1.1},this.labelSprite.scale.set(o.width,o.height),new e.Tween({opacity:0}).to({opacity:1},500).onUpdate(function(){q.opacity=this.opacity}).start();var t=this;if(new e.Tween({x:0,y:0}).to({x:50,y:50},2e3).easing(e.Easing.Elastic.Out).onUpdate(function(){t.marker.scale.set(this.x,this.y)}).delay(this.previous?t.opts.drawTime:0).start(),this.previous){var u,v,w,x,y,z,A,B,C,D,E,F,G=[],H=[];t.geometrySpline=new d.Geometry,u=new d.LineBasicMaterial({color:this.opts.lineColor,transparent:!0,linewidth:3,opacity:.5}),t.geometrySplineDotted=new d.Geometry,v=new d.LineBasicMaterial({color:this.opts.lineColor,linewidth:1,transparent:!0,opacity:.5}),w=(a-i.lat)/t.opts.lineSegments,x=(b-i.lon)/t.opts.lineSegments,y=f.mapPoint(i.lat,i.lon),G=[],H=[];for(var I=0;I=a.index&&(E.set(1.2*D.x,1.2*D.y,1.2*D.z),currentVert2.set(1.19*currentPoint2.x,1.19*currentPoint2.y,1.19*currentPoint2.z)),t.geometrySpline.verticesNeedUpdate=!0,t.geometrySplineDotted.verticesNeedUpdate=!0;G.length>0&&setTimeout(F,t.opts.drawTime/t.opts.lineSegments)},F(),this.scene.add(new d.Line(t.geometrySpline,u)),this.scene.add(new d.Line(t.geometrySplineDotted,v,d.LinePieces))}this.scene.add(this.marker),this.scene.add(this.labelSprite)};h.prototype.remove=function(){for(var a=0,b=this,c=function(d){for(var e=0;a>e;e++)d.geometrySpline.vertices[e].set(d.geometrySpline.vertices[e+1]),d.geometrySplineDotted.vertices[e].set(d.geometrySplineDotted.vertices[e+1]),d.geometrySpline.verticesNeedUpdate=!0,d.geometrySplineDotted.verticesNeedUpdate=!0;a++,a0,showTop:c.length>0,showSmoke:c.length>0,id:null};if(this.lat=a,this.lon=b,this.text=c,this.altitude=h,this.scene=i,this.smokeProvider=j,this.dateCreated=Date.now(),k)for(var t in s)void 0!=k[t]&&(s[t]=k[t]);this.opts=s,this.topVisible=s.showTop,this.smokeVisible=s.showSmoke,this.labelVisible=s.showLabel,this.lineGeometry=new d.Geometry,l=new d.LineBasicMaterial({color:s.lineColor,linewidth:s.lineWidth}),r=f.mapPoint(a,b),this.lineGeometry.vertices.push(new d.Vector3(r.x,r.y,r.z)),this.lineGeometry.vertices.push(new d.Vector3(r.x,r.y,r.z)),this.line=new d.Line(this.lineGeometry,l),m=f.createLabel(c,18,s.labelColor,s.font),n=new d.Texture(m),n.needsUpdate=!0,o=new d.SpriteMaterial({map:n,useScreenCoordinates:!1,opacity:0,depthTest:!0,fog:!0}),this.labelSprite=new d.Sprite(o),this.labelSprite.position={x:r.x*h*1.1,y:r.y*h+(r.y<0?-15:30),z:r.z*h*1.1},this.labelSprite.scale.set(m.width,m.height),p=new d.Texture(g(s.topColor)),p.needsUpdate=!0,q=new d.SpriteMaterial({map:p,depthTest:!0,fog:!0,opacity:0}),this.topSprite=new d.Sprite(q),this.topSprite.scale.set(20,20),this.topSprite.position.set(r.x*h,r.y*h,r.z*h),this.smokeVisible&&(this.smokeId=j.setFire(a,b,h));var u=this;(s.showTop||s.showLabel)&&new e.Tween({opacity:0}).to({opacity:1},500).onUpdate(function(){u.topVisible?q.opacity=this.opacity:q.opacity=0,u.labelVisible?o.opacity=this.opacity:o.opacity=0}).delay(1e3).start(),new e.Tween(r).to({x:r.x*h,y:r.y*h,z:r.z*h},1500).easing(e.Easing.Elastic.Out).onUpdate(function(){u.lineGeometry.vertices[1].x=this.x,u.lineGeometry.vertices[1].y=this.y,u.lineGeometry.vertices[1].z=this.z,u.lineGeometry.verticesNeedUpdate=!0}).start(),null!==this.opts.id&&void 0!==this.opts.id&&(this.labelSprite.name=this.opts.id,this.line.name=this.opts.id,this.topSprite.name=this.opts.id),this.scene.add(this.labelSprite),this.scene.add(this.line),this.scene.add(this.topSprite)};h.prototype.toString=function(){return""+this.lat+"_"+this.lon},h.prototype.changeAltitude=function(a){var b=f.mapPoint(this.lat,this.lon),c=this;new e.Tween({altitude:this.altitude}).to({altitude:a},1500).easing(e.Easing.Elastic.Out).onUpdate(function(){c.smokeVisible&&c.smokeProvider.changeAltitude(this.altitude,c.smokeId),c.topVisible&&c.topSprite.position.set(b.x*this.altitude,b.y*this.altitude,b.z*this.altitude),c.labelVisible&&(c.labelSprite.position={x:b.x*this.altitude*1.1,y:b.y*this.altitude+(b.y<0?-15:30),z:b.z*this.altitude*1.1}),c.lineGeometry.vertices[1].x=b.x*this.altitude,c.lineGeometry.vertices[1].y=b.y*this.altitude,c.lineGeometry.vertices[1].z=b.z*this.altitude,c.lineGeometry.verticesNeedUpdate=!0}).onComplete(function(){c.altitude=a}).start()},h.prototype.hideTop=function(){this.topVisible&&(this.topSprite.material.opacity=0,this.topVisible=!1)},h.prototype.showTop=function(){this.topVisible||(this.topSprite.material.opacity=1,this.topVisible=!0)},h.prototype.hideLabel=function(){this.labelVisible&&(this.labelSprite.material.opacity=0,this.labelVisible=!1)},h.prototype.showLabel=function(){this.labelVisible||(this.labelSprite.material.opacity=1,this.labelVisible=!0)},h.prototype.hideSmoke=function(){this.smokeVisible&&(this.smokeProvider.extinguish(this.smokeId),this.smokeVisible=!1)},h.prototype.showSmoke=function(){this.smokeVisible||(this.smokeId=this.smokeProvider.setFire(this.lat,this.lon,this.altitude),this.smokeVisible=!0)},h.prototype.age=function(){return Date.now()-this.dateCreated},h.prototype.remove=function(){this.scene.remove(this.labelSprite),this.scene.remove(this.line),this.scene.remove(this.topSprite),this.smokeVisible&&this.smokeProvider.extinguish(this.smokeId)},b.exports=h},{"./utils":21,three:12,"tween.js":13}],18:[function(a,b,c){var d=a("./TextureAnimator"),e=a("three"),f=a("./utils"),g=function(a,b,c,d,e,g,h,i){var j=a/c,k=Math.floor((a-d)/e),l=b-25,m=l/(a-d),n=0,o=0,p=0,q=f.hexToRgb(g);return f.renderToCanvas(a*b/c,b*c,function(c){for(var f=0;a>f;f++){f-p*j>=j&&(n=0,o+=b,p++);var g=n+25,l=o+Math.floor(b/2);c.lineWidth=2,c.strokeStyle=i;var r=Math.PI/16,s=-Math.PI+Math.PI/4,t=8,u=Math.floor(a-2*(a-d)/e)+1;d>f&&(t=t*f/d);for(var v=Math.floor((u-d)/2)+d,w=0;4>w;w++){if(c.beginPath(),d>f||f>=a)c.arc(g,l,t,w*Math.PI/2+s+r,w*Math.PI/2+s+Math.PI/2-2*r);else if(f>d&&v>f){var x=v-d,y=3*Math.PI/2,z=f-d,A=y/x,B=-Math.PI+Math.PI/4+r+A*z;c.arc(g,l,t,Math.max(w*Math.PI/2+s,B),Math.max(w*Math.PI/2+s+Math.PI/2-2*r,B+Math.PI/2-2*r))}else if(f>=v&&u>f){var x=u-v,y=2*w*Math.PI/4,z=f-v,A=y/x,B=Math.PI/2+Math.PI/4+r+A*z;c.arc(g,l,t,B,B+Math.PI/2-2*r)}else if(f>=u&&(a-u)/2+u>f){var x=(a-u)/2,y=Math.PI/2,z=f-u,A=y/x,B=w*(Math.PI/2)+Math.PI/4+r+A*z;c.arc(g,l,t,B,B+Math.PI/2-2*r)}else c.arc(g,l,t,w*Math.PI/2+s+r,w*Math.PI/2+s+Math.PI/2-2*r);c.stroke()}for(var C,D=0;e>D;D++)C=f-k*D-d,C>0&&b-25>C*m&&(c.strokeStyle="rgba("+q.r+","+q.g+","+q.b+","+(.9-C*m/(b-25))+")",c.lineWidth=2,c.beginPath(),c.arc(g,l,C*m,-Math.PI/12,Math.PI/12),c.stroke());c.fillStyle="#000",c.beginPath(),c.arc(g,l,3,0,2*Math.PI),c.fill(),c.strokeStyle=h,c.lineWidth=2,c.beginPath(),d>f?c.arc(g,l,3*f/d,0,2*Math.PI):c.arc(g,l,3,0,2*Math.PI),c.stroke(),n+=b}})},h=function(a,b,c,h,i,j,k){var l,m,n,o,p,q,r,s=f.mapPoint(a,b);s.x*=c,s.y*=c,s.z*=c;var m={numWaves:8,waveColor:"#FFF",coreColor:"#FF0000",shieldColor:"#FFF",size:1};if(this.lat=a,this.lon=b,this.altitude=c,this.scene=h,this.onRemoveList=[],n=50,o=100,p=10,q=Math.floor(n/8),i)for(var t in m)void 0!=i[t]&&(m[t]=i[t]);this.opts=m,j?(this.canvas=j,k?this.texture=k:(this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,r=Math.floor(n-2*(n-q)/m.numWaves)+1,this.animator=new d(this.texture,p,n/p,n,80,r))):(this.canvas=g(n,o,p,q,m.numWaves,m.waveColor,m.coreColor,m.shieldColor),this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,r=Math.floor(n-2*(n-q)/m.numWaves)+1,this.animator=new d(this.texture,p,n/p,n,80,r)),l=new e.PlaneGeometry(150*m.size,150*m.size,1,1),this.material=new e.MeshBasicMaterial({map:this.texture,depthTest:!1,transparent:!0}),this.mesh=new e.Mesh(l,this.material),this.mesh.tiltMultiplier=Math.PI/2*(1-Math.abs(a/90)),this.mesh.tiltDirection=a>0?-1:1,this.mesh.lon=b,this.mesh.position.set(s.x,s.y,s.z),this.mesh.rotation.z=-1*(a/90)*Math.PI/2,this.mesh.rotation.y=b/180*Math.PI,h.add(this.mesh)};h.prototype.changeAltitude=function(a){var b=f.mapPoint(this.lat,this.lon);b.x*=a,b.y*=a,b.z*=a,this.altitude=a,this.mesh.position.set(b.x,b.y,b.z)},h.prototype.changeCanvas=function(a,b,c,f){numFrames=50,pixels=100,rows=10,waveStart=Math.floor(numFrames/8),a?this.opts.numWaves=a:a=this.opts.numWaves,b?this.opts.waveColor=b:b=this.opts.waveColor,c?this.opts.coreColor=c:c=this.opts.coreColor,f?this.opts.shieldColor=f:f=this.opts.shieldColor,this.canvas=g(numFrames,pixels,rows,waveStart,a,b,c,f),this.texture=new e.Texture(this.canvas),this.texture.needsUpdate=!0,repeatAt=Math.floor(numFrames-2*(numFrames-waveStart)/a)+1,this.animator=new d(this.texture,rows,numFrames/rows,numFrames,80,repeatAt),this.material.map=this.texture},h.prototype.tick=function(a,b,c){this.mesh.lookAt(a),this.mesh.rotateZ(this.mesh.tiltDirection*Math.PI/2),this.mesh.rotateZ(Math.sin(b+this.mesh.lon/180*Math.PI)*this.mesh.tiltMultiplier*this.mesh.tiltDirection*-1),this.animator&&this.animator.update(c)},h.prototype.remove=function(){this.scene.remove(this.mesh);for(var a=0;a 0.0 && active > 0.0) {"," dt = mod(dt,1500.0);"," }"," float opacity = 1.0 - dt/ 1500.0;"," if (dt == 0.0 || active == 0.0){"," opacity = 0.0;"," }"," vec3 newPos = getPos(myStartLat, myStartLon - ( dt / 50.0));"," vColor = vec4( color, opacity );"," vec4 mvPosition = modelViewMatrix * vec4( newPos, 1.0 );"," gl_PointSize = 2.5 - (dt / 1500.0);"," gl_Position = projectionMatrix * mvPosition;","}"].join("\n"),g=["varying vec4 vColor;","void main()","{"," gl_FragColor = vColor;"," float depth = gl_FragCoord.z / gl_FragCoord.w;"," float fogFactor = smoothstep(1500.0, 1800.0, depth );"," vec3 fogColor = vec3(0.0);"," gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w), fogFactor );","}"].join("\n"),h=function(a,b){var c={smokeCount:5e3,smokePerPin:30,smokePerSecond:20};if(b)for(var e in c)void 0!==b[e]&&(c[e]=b[e]);this.opts=c,this.geometry=new d.Geometry,this.attributes={myStartTime:{type:"f",value:[]},myStartLat:{type:"f",value:[]},myStartLon:{type:"f",value:[]},altitude:{type:"f",value:[]},active:{type:"f",value:[]}},this.uniforms={currentTime:{type:"f",value:0},color:{type:"c",value:new d.Color("#aaa")}};for(var h=new d.ShaderMaterial({uniforms:this.uniforms,attributes:this.attributes,vertexShader:f,fragmentShader:g,transparent:!0}),e=0;ethis.tileDisplayDuration;)if(this.shutDownFlag&&this.currentTile>=e)this.done=!0, +this.shutDownCb();else{this.currentDisplayTime-=this.tileDisplayDuration,this.currentTile++,this.currentTile!=e||this.shutDownFlag||(this.currentTile=g);var c=this.currentTile%this.tilesHorizontal;a.offset.x=c/this.tilesHorizontal;var d=Math.floor(this.currentTile/this.tilesHorizontal);a.offset.y=1-d/this.tilesVertical-1/this.tilesVertical}},this.shutDown=function(a){_this.shutDownFlag=!0,_this.shutDownCb=a}};b.exports=e},{three:12}],21:[function(a,b,c){var d={renderToCanvas:function(a,b,c){var d=document.createElement("canvas");return d.width=a,d.height=b,c(d.getContext("2d")),d},mapPoint:function(a,b,c){c||(c=500);var d=(90-a)*Math.PI/180,e=(180-b)*Math.PI/180,f=c*Math.sin(d)*Math.cos(e),g=c*Math.cos(d),h=c*Math.sin(d)*Math.sin(e);return{x:f,y:g,z:h}},hexToRgb:function(a){var b=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;a=a.replace(b,function(a,b,c,d){return b+b+c+c+d+d});var c=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a);return c?{r:parseInt(c[1],16),g:parseInt(c[2],16),b:parseInt(c[3],16)}:null},createLabel:function(a,b,c,d,e){var f=document.createElement("canvas"),g=f.getContext("2d");g.font=b+"pt "+d;var h=g.measureText(a).width;return f.width=h,f.height=b+10,f.width%2&&f.width++,f.height%2&&f.height++,e&&(f.height+=30),g.font=b+"pt "+d,g.textAlign="center",g.textBaseline="middle",g.strokeStyle="black",g.miterLimit=2,g.lineJoin="circle",g.lineWidth=6,g.strokeText(a,f.width/2,f.height/2),g.lineWidth=2,g.fillStyle=c,g.fillText(a,f.width/2,f.height/2),e&&(g.strokeStyle=e,g.lineWidth=4,g.beginPath(),g.moveTo(0,f.height-10),g.lineTo(f.width-1,f.height-10),g.stroke()),f}};b.exports=d},{}]},{},[1]); \ No newline at end of file diff --git a/display/display.js b/display/display.js index 494ca28..1e49eac 100644 --- a/display/display.js +++ b/display/display.js @@ -28,7 +28,8 @@ function createGlobe(){ // data: [], // tiles: [], // viewAngle: .1, // North-South camera angle; between -Math.PI and Math.PI - // cameraAngle: Math.PI // East-West camera angle; between -Math.PI and Math.PI + // cameraAngle: Math.PI, // East-West camera angle; between -Math.PI and Math.PI + // viewAngleResetTime: 30000 // time in MS to wait before reseting viewAngle back to default // }; $("#globe").append(globe.domElement); diff --git a/src/Globe.js b/src/Globe.js index acf86d5..ef67435 100644 --- a/src/Globe.js +++ b/src/Globe.js @@ -37,7 +37,6 @@ var addInitialData = function(){ } }; - var createParticles = function(){ if(this.hexGrid){ @@ -258,17 +257,36 @@ var createIntroLines = function(){ var createMouseBehaviors = function(globe){ var mouseDown = false, - mousePos = 0, + mousePos = {x: 0, y: 0}, lastTime = Date.now(), - movedSinceMouseDown = false, + distanceSinceMouseDown = 0, mouseTimeout, + verticalTimeout, mouseVector = new THREE.Vector3(0,0,0), projector = new THREE.Projector(); - - globe.domElement.onmousedown = function(e){ mouseDown = true; mousePos = e.clientX; lastTime = Date.now(); movedSinceMouseDown=false;}; - globe.domElement.onmouseup = function(e){ mouseDown = false; globe.resetRotationSpeed()}; - globe.domElement.onmouseleave = function(e){ mouseDown = false; globe.resetRotationSpeed();}; + var onmouseup = function(){ + mouseDown = false; + globe.resetRotationSpeed(); + clearTimeout(verticalTimeout); + verticalTimeout = setTimeout(function(){ + new TWEEN.Tween( {viewAngle: globe.viewAngle}) + .easing( TWEEN.Easing.Quadratic.InOut) + .to( {viewAngle: globe.defaultViewAngle}, 1000 ) + .onUpdate(function(){ + globe.viewAngle = this.viewAngle; + }).start(); + + },globe.viewAngleResetTime); + }; + + var onmousedown = function(e){ + clearTimeout(verticalTimeout); + mouseDown = true; + mousePos = {x: e.clientX, y: e.clientY}; + lastTime = Date.now(); + movedSinceMouseDown=0; + }; var onmousemove = function(e, secondCall){ @@ -277,12 +295,13 @@ var createMouseBehaviors = function(globe){ var diff = Date.now() - lastTime; if(mouseDown && diff){ - movedSinceMouseDown = true; + movedSinceMouseDown += Math.abs(e.clientX-mousePos.x) + Math.abs(e.clientY-mousePos.y); - globe.setRotationSpeed(((e.clientX-mousePos)/globe.width) / (diff/1000)); + globe.setRotationSpeed(((e.clientX-mousePos.x)/globe.width) / (diff/1000)); + globe.setVerticalRotationSpeed(((e.clientY-mousePos.y)/globe.height / 2) / (diff/1000)); lastTime = Date.now(); - mousePos = e.clientX; + mousePos = {x: e.clientX, y: e.clientY}; clearTimeout(mouseTimeout); if(!secondCall){ mouseTimeout = setTimeout(function(){onmousemove(e, true)},100); @@ -291,7 +310,7 @@ var createMouseBehaviors = function(globe){ }; var onclick = function (e) { - if(!movedSinceMouseDown){ + if(movedSinceMouseDown < 50){ var raycaster = projector.pickingRay( mouseVector.clone(), globe.camera ); var intersects = raycaster.intersectObjects(globe.scene.children); var minDistance = globe.cameraDistance * 1.1; @@ -315,6 +334,9 @@ var createMouseBehaviors = function(globe){ } } + globe.domElement.onmousedown = onmousedown; + globe.domElement.onmouseup = onmouseup; + globe.domElement.onmouseleave = onmouseup; globe.domElement.onmousemove = onmousemove; globe.domElement.onclick = onclick; @@ -360,7 +382,8 @@ function Globe(width, height, opts){ data: [], tiles: [], viewAngle: .1, - cameraAngle: Math.PI + cameraAngle: Math.PI, + viewAngleResetTime: 30000 }; for(var i in defaults){ @@ -378,6 +401,8 @@ function Globe(width, height, opts){ this.rotationSpeed = 1000 * 1/this.dayLength; } + this.verticalRotationSpeed = 0; + this.setScale(this.scale); this.renderer = new THREE.WebGLRenderer( { antialias: true } ); @@ -395,6 +420,7 @@ function Globe(width, height, opts){ } this.defaultRotationSpeed = this.rotationSpeed; + this.defaultViewAngle = this.viewAngle; createMouseBehaviors(this); @@ -643,8 +669,13 @@ Globe.prototype.setRotationSpeed = function(rotationSpeed){ this.rotationSpeed = rotationSpeed; } +Globe.prototype.setVerticalRotationSpeed = function(rotationSpeed){ + this.verticalRotationSpeed = rotationSpeed; +} + Globe.prototype.resetRotationSpeed = function(){ this.rotationSpeed = this.defaultRotationSpeed; + this.verticalRotationSpeed = 0; } Globe.prototype.tick = function(){ @@ -672,8 +703,12 @@ Globe.prototype.tick = function(){ var renderTime = new Date() - this.lastRenderDate; this.lastRenderDate = new Date(); var rotateCameraBy = this.rotationSpeed * renderTime/1000 * 2 * Math.PI; + var rotateVerticalCameraBy = this.verticalRotationSpeed * renderTime/1000 * 2 * Math.PI; this.cameraAngle += rotateCameraBy; + this.viewAngle += rotateVerticalCameraBy; + this.viewAngle = Math.min(Math.PI/2, this.viewAngle); + this.viewAngle = Math.max(-Math.PI/2, this.viewAngle); if(!this.active){ this.cameraDistance += (1000 * renderTime/1000); From 4892339f34a366175ff574ad268f0498c0be9f3f Mon Sep 17 00:00:00 2001 From: Rob Scanlon Date: Fri, 20 Aug 2021 09:56:14 -0400 Subject: [PATCH 5/5] Fix line endings. --- build/encom-globe.js | 80098 ++++++++++++++++++++--------------------- 1 file changed, 40049 insertions(+), 40049 deletions(-) diff --git a/build/encom-globe.js b/build/encom-globe.js index 3e28b27..448d75f 100644 --- a/build/encom-globe.js +++ b/build/encom-globe.js @@ -2853,40055 +2853,40055 @@ Quadtree2Validator.prototype = { module.exports = Quadtree2Validator; },{"./quadtree2helper":9,"vec2":7}],12:[function(require,module,exports){ -var self = self || {};/** - * @author mrdoob / http://mrdoob.com/ - * @author Larry Battle / http://bateru.com/news - * @author bhouston / http://exocortex.com - */ - -var THREE = { REVISION: '66.87' }; - -self.console = self.console || { - - info: function () {}, - log: function () {}, - debug: function () {}, - warn: function () {}, - error: function () {} - -}; - -// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ -// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating - -// requestAnimationFrame polyfill by Erik Möller -// fixes from Paul Irish and Tino Zijdel -// using 'self' instead of 'window' for compatibility with both NodeJS and IE10. -( function () { - - var lastTime = 0; - var vendors = [ 'ms', 'moz', 'webkit', 'o' ]; - - for ( var x = 0; x < vendors.length && !self.requestAnimationFrame; ++ x ) { - - self.requestAnimationFrame = self[ vendors[ x ] + 'RequestAnimationFrame' ]; - self.cancelAnimationFrame = self[ vendors[ x ] + 'CancelAnimationFrame' ] || self[ vendors[ x ] + 'CancelRequestAnimationFrame' ]; - - } - - if ( self.requestAnimationFrame === undefined && self['setTimeout'] !== undefined ) { - - self.requestAnimationFrame = function ( callback ) { - - var currTime = Date.now(), timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ); - var id = self.setTimeout( function() { callback( currTime + timeToCall ); }, timeToCall ); - lastTime = currTime + timeToCall; - return id; - - }; - - } - - if( self.cancelAnimationFrame === undefined && self['clearTimeout'] !== undefined ) { - - self.cancelAnimationFrame = function ( id ) { self.clearTimeout( id ) }; - - } - -}() ); - -THREE.ExceptionErrorHandler = function( message, optionalData ) { - console.error( message ); - console.error( optionalData ); - var error = new Error( message ); - error.optionalData = optionalData; - throw error; -}; - -THREE.ConsoleErrorHandler = function( message, optionalData ) { - console.error( message ); - console.error( optionalData ); -}; - -THREE.ConsoleWarningHandler = function( message, optionalData ) { - console.warn( message ); - console.warn( optionalData ); -}; - -THREE.NullHandler = function( message, optionalData ) { -}; - -// the default error handler is exception -THREE.onerror = THREE.ExceptionErrorHandler; - -THREE.onwarning = THREE.ConsoleWarningHandler; - -// GL STATE CONSTANTS - -THREE.CullFaceNone = 0; -THREE.CullFaceBack = 1; -THREE.CullFaceFront = 2; -THREE.CullFaceFrontBack = 3; - -THREE.FrontFaceDirectionCW = 0; -THREE.FrontFaceDirectionCCW = 1; - -// SHADOWING TYPES - -THREE.BasicShadowMap = 0; -THREE.PCFShadowMap = 1; -THREE.PCFSoftShadowMap = 2; - -// MATERIAL CONSTANTS - -// side - -THREE.FrontSide = 0; -THREE.BackSide = 1; -THREE.DoubleSide = 2; - -// shading - -THREE.NoShading = 0; -THREE.FlatShading = 1; -THREE.SmoothShading = 2; - -// colors - -THREE.NoColors = 0; -THREE.FaceColors = 1; -THREE.VertexColors = 2; - -// blending modes - -THREE.NoBlending = 0; -THREE.NormalBlending = 1; -THREE.AdditiveBlending = 2; -THREE.SubtractiveBlending = 3; -THREE.MultiplyBlending = 4; -THREE.CustomBlending = 5; - -// custom blending equations -// (numbers start from 100 not to clash with other -// mappings to OpenGL constants defined in Texture.js) - -THREE.AddEquation = 100; -THREE.SubtractEquation = 101; -THREE.ReverseSubtractEquation = 102; - -// custom blending destination factors - -THREE.ZeroFactor = 200; -THREE.OneFactor = 201; -THREE.SrcColorFactor = 202; -THREE.OneMinusSrcColorFactor = 203; -THREE.SrcAlphaFactor = 204; -THREE.OneMinusSrcAlphaFactor = 205; -THREE.DstAlphaFactor = 206; -THREE.OneMinusDstAlphaFactor = 207; - -// custom blending source factors - -//THREE.ZeroFactor = 200; -//THREE.OneFactor = 201; -//THREE.SrcAlphaFactor = 204; -//THREE.OneMinusSrcAlphaFactor = 205; -//THREE.DstAlphaFactor = 206; -//THREE.OneMinusDstAlphaFactor = 207; -THREE.DstColorFactor = 208; -THREE.OneMinusDstColorFactor = 209; -THREE.SrcAlphaSaturateFactor = 210; - - -// TEXTURE CONSTANTS - -THREE.MultiplyOperation = 0; -THREE.MixOperation = 1; -THREE.AddOperation = 2; - -// Mapping modes - -THREE.UVMapping = function () {}; - -THREE.CubeReflectionMapping = function () {}; -THREE.CubeRefractionMapping = function () {}; - -THREE.SphericalReflectionMapping = function () {}; -THREE.SphericalRefractionMapping = function () {}; - -// Wrapping modes - -THREE.RepeatWrapping = 1000; -THREE.ClampToEdgeWrapping = 1001; -THREE.MirroredRepeatWrapping = 1002; - -// Filters - -THREE.NearestFilter = 1003; -THREE.NearestMipMapNearestFilter = 1004; -THREE.NearestMipMapLinearFilter = 1005; -THREE.LinearFilter = 1006; -THREE.LinearMipMapNearestFilter = 1007; -THREE.LinearMipMapLinearFilter = 1008; - -// Texture Decoders - -THREE.Linear = 3000; -THREE.sRGB = 3001; -THREE.RGBE = 3002; -THREE.LogLUV = 3003; -THREE.RGBM7 = 3004; -THREE.RGBM16 = 3005; - -// Data types - -THREE.UnsignedByteType = 1009; -THREE.ByteType = 1010; -THREE.ShortType = 1011; -THREE.UnsignedShortType = 1012; -THREE.IntType = 1013; -THREE.UnsignedIntType = 1014; -THREE.FloatType = 1015; -THREE.HalfType = 2005; - -// Pixel types - -//THREE.UnsignedByteType = 1009; -THREE.UnsignedShort4444Type = 1016; -THREE.UnsignedShort5551Type = 1017; -THREE.UnsignedShort565Type = 1018; - -// Pixel formats - -THREE.AlphaFormat = 1019; -THREE.RGBFormat = 1020; -THREE.RGBAFormat = 1021; -THREE.LuminanceFormat = 1022; -THREE.LuminanceAlphaFormat = 1023; - -// Compressed texture formats - -THREE.RGB_S3TC_DXT1_Format = 2001; -THREE.RGBA_S3TC_DXT1_Format = 2002; -THREE.RGBA_S3TC_DXT3_Format = 2003; -THREE.RGBA_S3TC_DXT5_Format = 2004; - -/* -// Potential future PVRTC compressed texture formats -THREE.RGB_PVRTC_4BPPV1_Format = 2100; -THREE.RGB_PVRTC_2BPPV1_Format = 2101; -THREE.RGBA_PVRTC_4BPPV1_Format = 2102; -THREE.RGBA_PVRTC_2BPPV1_Format = 2103; -*/ - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Color = function ( color ) { - - if ( arguments.length === 3 ) { - - return this.setRGB( arguments[ 0 ], arguments[ 1 ], arguments[ 2 ] ); - - } - - return this.set( color ) - -}; - -THREE.Color.prototype = { - - constructor: THREE.Color, - - r: 1, g: 1, b: 1, - - set: function ( value ) { - - if ( value instanceof THREE.Color ) { - - this.copy( value ); - - } else if ( typeof value === 'number' ) { - - this.setHex( value ); - - } else if ( typeof value === 'string' ) { - - this.setStyle( value ); - - } - - return this; - - }, - - setHex: function ( hex ) { - - hex = Math.floor( hex ); - - this.r = ( hex >> 16 & 255 ) / 255; - this.g = ( hex >> 8 & 255 ) / 255; - this.b = ( hex & 255 ) / 255; - - return this; - - }, - - setRGB: function ( r, g, b ) { - - this.r = r; - this.g = g; - this.b = b; - - return this; - - }, - - setHSL: function ( h, s, l ) { - - // h,s,l ranges are in 0.0 - 1.0 - - if ( s === 0 ) { - - this.r = this.g = this.b = l; - - } else { - - var hue2rgb = function ( p, q, t ) { - - if ( t < 0 ) t += 1; - if ( t > 1 ) t -= 1; - if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; - if ( t < 1 / 2 ) return q; - if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); - return p; - - }; - - var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); - var q = ( 2 * l ) - p; - - this.r = hue2rgb( q, p, h + 1 / 3 ); - this.g = hue2rgb( q, p, h ); - this.b = hue2rgb( q, p, h - 1 / 3 ); - - } - - return this; - - }, - - setStyle: function ( style ) { - - // rgb(255,0,0) - - if ( /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test( style ) ) { - - var color = /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec( style ); - - this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; - this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; - this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; - - return this; - - } - - // rgb(100%,0%,0%) - - if ( /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test( style ) ) { - - var color = /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec( style ); - - this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; - this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; - this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; - - return this; - - } - - // #ff0000 - - if ( /^\#([0-9a-f]{6})$/i.test( style ) ) { - - var color = /^\#([0-9a-f]{6})$/i.exec( style ); - - this.setHex( parseInt( color[ 1 ], 16 ) ); - - return this; - - } - - // #f00 - - if ( /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test( style ) ) { - - var color = /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec( style ); - - this.setHex( parseInt( color[ 1 ] + color[ 1 ] + color[ 2 ] + color[ 2 ] + color[ 3 ] + color[ 3 ], 16 ) ); - - return this; - - } - - // red - - if ( /^(\w+)$/i.test( style ) ) { - - this.setHex( THREE.ColorKeywords[ style ] ); - - return this; - - } - - - }, - - copy: function ( color ) { - - this.r = color.r; - this.g = color.g; - this.b = color.b; - - return this; - - }, - - copyGammaToLinear: function ( color ) { - - this.r = color.r * color.r; - this.g = color.g * color.g; - this.b = color.b * color.b; - - return this; - - }, - - copyLinearToGamma: function ( color ) { - - this.r = Math.sqrt( color.r ); - this.g = Math.sqrt( color.g ); - this.b = Math.sqrt( color.b ); - - return this; - - }, - - convertGammaToLinear: function () { - - var r = this.r, g = this.g, b = this.b; - - this.r = r * r; - this.g = g * g; - this.b = b * b; - - return this; - - }, - - convertLinearToGamma: function () { - - this.r = Math.sqrt( this.r ); - this.g = Math.sqrt( this.g ); - this.b = Math.sqrt( this.b ); - - return this; - - }, - - getHex: function () { - - return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; - - }, - - getHexString: function () { - - return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); - - }, - - getHSL: function ( optionalTarget ) { - - // h,s,l ranges are in 0.0 - 1.0 - - var hsl = optionalTarget || { h: 0, s: 0, l: 0 }; - - var r = this.r, g = this.g, b = this.b; - - var max = Math.max( r, g, b ); - var min = Math.min( r, g, b ); - - var hue, saturation; - var lightness = ( min + max ) / 2.0; - - if ( min === max ) { - - hue = 0; - saturation = 0; - - } else { - - var delta = max - min; - - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); - - switch ( max ) { - - case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; - case g: hue = ( b - r ) / delta + 2; break; - case b: hue = ( r - g ) / delta + 4; break; - - } - - hue /= 6; - - } - - hsl.h = hue; - hsl.s = saturation; - hsl.l = lightness; - - return hsl; - - }, - - getStyle: function () { - - return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; - - }, - - offsetHSL: function ( h, s, l ) { - - var hsl = this.getHSL(); - - hsl.h += h; hsl.s += s; hsl.l += l; - - this.setHSL( hsl.h, hsl.s, hsl.l ); - - return this; - - }, - - add: function ( color ) { - - this.r += color.r; - this.g += color.g; - this.b += color.b; - - return this; - - }, - - addColors: function ( color1, color2 ) { - - this.r = color1.r + color2.r; - this.g = color1.g + color2.g; - this.b = color1.b + color2.b; - - return this; - - }, - - addScalar: function ( s ) { - - this.r += s; - this.g += s; - this.b += s; - - return this; - - }, - - multiply: function ( color ) { - - this.r *= color.r; - this.g *= color.g; - this.b *= color.b; - - return this; - - }, - - multiplyScalar: function ( s ) { - - this.r *= s; - this.g *= s; - this.b *= s; - - return this; - - }, - - lerp: function ( color, alpha ) { - - this.r += ( color.r - this.r ) * alpha; - this.g += ( color.g - this.g ) * alpha; - this.b += ( color.b - this.b ) * alpha; - - return this; - - }, - - equals: function ( c ) { - - return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); - - }, - - fromArray: function ( array ) { - - this.r = array[ 0 ]; - this.g = array[ 1 ]; - this.b = array[ 2 ]; - - return this; - - }, - - toArray: function () { - - return [ this.r, this.g, this.b ]; - - }, - - clone: function () { - - return new THREE.Color().setRGB( this.r, this.g, this.b ); - - } - -}; - -THREE.ColorKeywords = { "aliceblue": 0xF0F8FF, "antiquewhite": 0xFAEBD7, "aqua": 0x00FFFF, "aquamarine": 0x7FFFD4, "azure": 0xF0FFFF, -"beige": 0xF5F5DC, "bisque": 0xFFE4C4, "black": 0x000000, "blanchedalmond": 0xFFEBCD, "blue": 0x0000FF, "blueviolet": 0x8A2BE2, -"brown": 0xA52A2A, "burlywood": 0xDEB887, "cadetblue": 0x5F9EA0, "chartreuse": 0x7FFF00, "chocolate": 0xD2691E, "coral": 0xFF7F50, -"cornflowerblue": 0x6495ED, "cornsilk": 0xFFF8DC, "crimson": 0xDC143C, "cyan": 0x00FFFF, "darkblue": 0x00008B, "darkcyan": 0x008B8B, -"darkgoldenrod": 0xB8860B, "darkgray": 0xA9A9A9, "darkgreen": 0x006400, "darkgrey": 0xA9A9A9, "darkkhaki": 0xBDB76B, "darkmagenta": 0x8B008B, -"darkolivegreen": 0x556B2F, "darkorange": 0xFF8C00, "darkorchid": 0x9932CC, "darkred": 0x8B0000, "darksalmon": 0xE9967A, "darkseagreen": 0x8FBC8F, -"darkslateblue": 0x483D8B, "darkslategray": 0x2F4F4F, "darkslategrey": 0x2F4F4F, "darkturquoise": 0x00CED1, "darkviolet": 0x9400D3, -"deeppink": 0xFF1493, "deepskyblue": 0x00BFFF, "dimgray": 0x696969, "dimgrey": 0x696969, "dodgerblue": 0x1E90FF, "firebrick": 0xB22222, -"floralwhite": 0xFFFAF0, "forestgreen": 0x228B22, "fuchsia": 0xFF00FF, "gainsboro": 0xDCDCDC, "ghostwhite": 0xF8F8FF, "gold": 0xFFD700, -"goldenrod": 0xDAA520, "gray": 0x808080, "green": 0x008000, "greenyellow": 0xADFF2F, "grey": 0x808080, "honeydew": 0xF0FFF0, "hotpink": 0xFF69B4, -"indianred": 0xCD5C5C, "indigo": 0x4B0082, "ivory": 0xFFFFF0, "khaki": 0xF0E68C, "lavender": 0xE6E6FA, "lavenderblush": 0xFFF0F5, "lawngreen": 0x7CFC00, -"lemonchiffon": 0xFFFACD, "lightblue": 0xADD8E6, "lightcoral": 0xF08080, "lightcyan": 0xE0FFFF, "lightgoldenrodyellow": 0xFAFAD2, "lightgray": 0xD3D3D3, -"lightgreen": 0x90EE90, "lightgrey": 0xD3D3D3, "lightpink": 0xFFB6C1, "lightsalmon": 0xFFA07A, "lightseagreen": 0x20B2AA, "lightskyblue": 0x87CEFA, -"lightslategray": 0x778899, "lightslategrey": 0x778899, "lightsteelblue": 0xB0C4DE, "lightyellow": 0xFFFFE0, "lime": 0x00FF00, "limegreen": 0x32CD32, -"linen": 0xFAF0E6, "magenta": 0xFF00FF, "maroon": 0x800000, "mediumaquamarine": 0x66CDAA, "mediumblue": 0x0000CD, "mediumorchid": 0xBA55D3, -"mediumpurple": 0x9370DB, "mediumseagreen": 0x3CB371, "mediumslateblue": 0x7B68EE, "mediumspringgreen": 0x00FA9A, "mediumturquoise": 0x48D1CC, -"mediumvioletred": 0xC71585, "midnightblue": 0x191970, "mintcream": 0xF5FFFA, "mistyrose": 0xFFE4E1, "moccasin": 0xFFE4B5, "navajowhite": 0xFFDEAD, -"navy": 0x000080, "oldlace": 0xFDF5E6, "olive": 0x808000, "olivedrab": 0x6B8E23, "orange": 0xFFA500, "orangered": 0xFF4500, "orchid": 0xDA70D6, -"palegoldenrod": 0xEEE8AA, "palegreen": 0x98FB98, "paleturquoise": 0xAFEEEE, "palevioletred": 0xDB7093, "papayawhip": 0xFFEFD5, "peachpuff": 0xFFDAB9, -"peru": 0xCD853F, "pink": 0xFFC0CB, "plum": 0xDDA0DD, "powderblue": 0xB0E0E6, "purple": 0x800080, "red": 0xFF0000, "rosybrown": 0xBC8F8F, -"royalblue": 0x4169E1, "saddlebrown": 0x8B4513, "salmon": 0xFA8072, "sandybrown": 0xF4A460, "seagreen": 0x2E8B57, "seashell": 0xFFF5EE, -"sienna": 0xA0522D, "silver": 0xC0C0C0, "skyblue": 0x87CEEB, "slateblue": 0x6A5ACD, "slategray": 0x708090, "slategrey": 0x708090, "snow": 0xFFFAFA, -"springgreen": 0x00FF7F, "steelblue": 0x4682B4, "tan": 0xD2B48C, "teal": 0x008080, "thistle": 0xD8BFD8, "tomato": 0xFF6347, "turquoise": 0x40E0D0, -"violet": 0xEE82EE, "wheat": 0xF5DEB3, "white": 0xFFFFFF, "whitesmoke": 0xF5F5F5, "yellow": 0xFFFF00, "yellowgreen": 0x9ACD32 }; - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://exocortex.com - */ - -THREE.Quaternion = function ( x, y, z, w ) { - - this._x = x || 0; - this._y = y || 0; - this._z = z || 0; - this._w = ( w !== undefined ) ? w : 1; - -}; - -THREE.Quaternion.prototype = { - - constructor: THREE.Quaternion, - - _x: 0,_y: 0, _z: 0, _w: 0, - - _euler: undefined, - - _updateEuler: function ( callback ) { - - if ( this._euler !== undefined ) { - - this._euler.setFromQuaternion( this, undefined, false ); - - } - - }, - - get x () { - - return this._x; - - }, - - set x ( value ) { - - this._x = value; - this._updateEuler(); - - }, - - get y () { - - return this._y; - - }, - - set y ( value ) { - - this._y = value; - this._updateEuler(); - - }, - - get z () { - - return this._z; - - }, - - set z ( value ) { - - this._z = value; - this._updateEuler(); - - }, - - get w () { - - return this._w; - - }, - - set w ( value ) { - - this._w = value; - this._updateEuler(); - - }, - - set: function ( x, y, z, w ) { - - this._x = x; - this._y = y; - this._z = z; - this._w = w; - - this._updateEuler(); - - return this; - - }, - - copy: function ( quaternion ) { - - this._x = quaternion._x; - this._y = quaternion._y; - this._z = quaternion._z; - this._w = quaternion._w; - - this._updateEuler(); - - return this; - - }, - - setFromEuler: function ( euler, update ) { - - if ( ! ( euler instanceof THREE.Euler ) ) return THREE.onerror( 'expecting a Euler', euler ); - - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m - - var c1 = Math.cos( euler._x / 2 ); - var c2 = Math.cos( euler._y / 2 ); - var c3 = Math.cos( euler._z / 2 ); - var s1 = Math.sin( euler._x / 2 ); - var s2 = Math.sin( euler._y / 2 ); - var s3 = Math.sin( euler._z / 2 ); - - if ( euler.order === 'XYZ' ) { - - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - - } else if ( euler.order === 'YXZ' ) { - - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - - } else if ( euler.order === 'ZXY' ) { - - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - - } else if ( euler.order === 'ZYX' ) { - - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - - } else if ( euler.order === 'YZX' ) { - - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - - } else if ( euler.order === 'XZY' ) { - - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - - } - - if ( update !== false ) this._updateEuler(); - - return this; - - }, - - setFromAxisAngle: function ( axis, angle ) { - - // from http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - // axis have to be normalized - - var halfAngle = angle / 2, s = Math.sin( halfAngle ); - - this._x = axis.x * s; - this._y = axis.y * s; - this._z = axis.z * s; - this._w = Math.cos( halfAngle ); - - this._updateEuler(); - - return this; - - }, - - setFromRotationMatrix: function ( m ) { - - //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - var te = m.elements, - - m11 = te[0], m12 = te[4], m13 = te[8], - m21 = te[1], m22 = te[5], m23 = te[9], - m31 = te[2], m32 = te[6], m33 = te[10], - - trace = m11 + m22 + m33, - s; - - if ( trace > 0 ) { - - s = 0.5 / Math.sqrt( trace + 1.0 ); - - this._w = 0.25 / s; - this._x = ( m32 - m23 ) * s; - this._y = ( m13 - m31 ) * s; - this._z = ( m21 - m12 ) * s; - - } else if ( m11 > m22 && m11 > m33 ) { - - s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); - - this._w = (m32 - m23 ) / s; - this._x = 0.25 * s; - this._y = (m12 + m21 ) / s; - this._z = (m13 + m31 ) / s; - - } else if ( m22 > m33 ) { - - s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); - - this._w = (m13 - m31 ) / s; - this._x = (m12 + m21 ) / s; - this._y = 0.25 * s; - this._z = (m23 + m32 ) / s; - - } else { - - s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); - - this._w = ( m21 - m12 ) / s; - this._x = ( m13 + m31 ) / s; - this._y = ( m23 + m32 ) / s; - this._z = 0.25 * s; - - } - - this._updateEuler(); - - return this; - - }, - - inverse: function () { - - this.conjugate().normalize(); - - return this; - - }, - - add: function ( q ) { - - this._x += q._x; - this._y += q._y; - this._z += q._z; - this._w += q._w; - - return this; - - }, - - sub: function ( q ) { - - this._x -= q._x; - this._y -= q._y; - this._z -= q._z; - this._w -= q._w; - - return this; - - }, - - multiplyScalar: function ( s ) { - - this._x *= s; - this._y *= s; - this._z *= s; - this._w *= s; - - return this; - - }, - - conjugate: function () { - - this._x *= -1; - this._y *= -1; - this._z *= -1; - - this._updateEuler(); - - return this; - - }, - - lengthSq: function () { - - return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; - - }, - - length: function () { - - return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); - - }, - - normalize: function () { - - var l = this.length(); - - if ( l === 0 ) { - - this._x = 0; - this._y = 0; - this._z = 0; - this._w = 1; - - } else { - - l = 1 / l; - - this._x = this._x * l; - this._y = this._y * l; - this._z = this._z * l; - this._w = this._w * l; - - } - - return this; - - }, - - multiply: function ( q, p ) { - - if ( p !== undefined ) { - - THREE.onwarning( 'DEPRECATED: Quaternion\'s .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); - return this.multiplyQuaternions( q, p ); - - } - - return this.multiplyQuaternions( this, q ); - - }, - - multiplyQuaternions: function ( a, b ) { - - // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm - - var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; - var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; - - this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; - this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; - this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; - this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - - this._updateEuler(); - - return this; - - }, - - multiplyVector3: function ( vector ) { - - THREE.onwarning( 'DEPRECATED: Quaternion\'s .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); - return vector.applyQuaternion( this ); - - }, - - slerp: function ( qb, t ) { - - var x = this._x, y = this._y, z = this._z, w = this._w; - - // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ - - var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; - - if ( cosHalfTheta < 0 ) { - - this._w = -qb._w; - this._x = -qb._x; - this._y = -qb._y; - this._z = -qb._z; - - cosHalfTheta = -cosHalfTheta; - - } else { - - this.copy( qb ); - - } - - if ( cosHalfTheta >= 1.0 ) { - - this._w = w; - this._x = x; - this._y = y; - this._z = z; - - return this; - - } - - var halfTheta = Math.acos( cosHalfTheta ); - var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta ); - - if ( Math.abs( sinHalfTheta ) < 0.001 ) { - - this._w = 0.5 * ( w + this._w ); - this._x = 0.5 * ( x + this._x ); - this._y = 0.5 * ( y + this._y ); - this._z = 0.5 * ( z + this._z ); - - return this; - - } - - var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, - ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; - - this._w = ( w * ratioA + this._w * ratioB ); - this._x = ( x * ratioA + this._x * ratioB ); - this._y = ( y * ratioA + this._y * ratioB ); - this._z = ( z * ratioA + this._z * ratioB ); - - this._updateEuler(); - - return this; - - }, - - equals: function ( quaternion ) { - - return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); - - }, - - fromArray: function ( array ) { - - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - this._w = array[ 3 ]; - - this._updateEuler(); - - return this; - - }, - - toArray: function () { - - return [ this._x, this._y, this._z, this._w ]; - - }, - - clone: function () { - - return new THREE.Quaternion( this._x, this._y, this._z, this._w ); - - } - -}; - -THREE.Quaternion.slerp = function ( qa, qb, qm, t ) { - - return qm.copy( qa ).slerp( qb, t ); - -} - -/** - * @author mrdoob / http://mrdoob.com/ - * @author philogb / http://blog.thejit.org/ - * @author egraether / http://egraether.com/ - * @author zz85 / http://www.lab4games.net/zz85/blog - */ - -THREE.Vector2 = function ( x, y ) { - - this.x = x || 0; - this.y = y || 0; - -}; - -THREE.Vector2.prototype = { - - constructor: THREE.Vector2, - - set: function ( x, y ) { - - this.x = x; - this.y = y; - - return this; - - }, - - setX: function ( x ) { - - this.x = x; - - return this; - - }, - - setY: function ( y ) { - - this.y = y; - - return this; - - }, - - - setComponent: function ( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - default: return THREE.onerror( 'index is out of range: ' + index ); - - } - - }, - - getComponent: function ( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - default: return THREE.onerror( 'index is out of range: ' + index ); - - } - - }, - - copy: function ( v ) { - - this.x = v.x; - this.y = v.y; - - return this; - - }, - - add: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.onwarning( 'DEPRECATED: Vector2\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); - return this.addVectors( v, w ); - - } - - this.x += v.x; - this.y += v.y; - - return this; - - }, - - addVectors: function ( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - - return this; - - }, - - addScalar: function ( s ) { - - this.x += s; - this.y += s; - - return this; - - }, - - sub: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.onwarning( 'DEPRECATED: Vector2\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); - - } - - this.x -= v.x; - this.y -= v.y; - - return this; - - }, - - subVectors: function ( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - - return this; - - }, - - multiplyScalar: function ( s ) { - - this.x *= s; - this.y *= s; - - return this; - - }, - - divideScalar: function ( scalar ) { - - if ( scalar !== 0 ) { - - var invScalar = 1 / scalar; - - this.x *= invScalar; - this.y *= invScalar; - - } else { - - this.x = 0; - this.y = 0; - - } - - return this; - - }, - - min: function ( v ) { - - if ( this.x > v.x ) { - - this.x = v.x; - - } - - if ( this.y > v.y ) { - - this.y = v.y; - - } - - return this; - - }, - - max: function ( v ) { - - if ( this.x < v.x ) { - - this.x = v.x; - - } - - if ( this.y < v.y ) { - - this.y = v.y; - - } - - return this; - - }, - - clamp: function ( min, max ) { - - // This function assumes min < max, if this assumption isn't true it will not operate correctly - - if ( this.x < min.x ) { - - this.x = min.x; - - } else if ( this.x > max.x ) { - - this.x = max.x; - - } - - if ( this.y < min.y ) { - - this.y = min.y; - - } else if ( this.y > max.y ) { - - this.y = max.y; - - } - - return this; - }, - - clampScalar: ( function () { - - var min, max; - - return function ( minVal, maxVal ) { - - if ( min === undefined ) { - - min = new THREE.Vector2(); - max = new THREE.Vector2(); - - } - - min.set( minVal, minVal ); - max.set( maxVal, maxVal ); - - return this.clamp( min, max ); - - }; - - } )(), - - floor: function () { - - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - - return this; - - }, - - ceil: function () { - - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - - return this; - - }, - - round: function () { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - - return this; - - }, - - roundToZero: function () { - - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - - return this; - - }, - - negate: function () { - - return this.multiplyScalar( - 1 ); - - }, - - dot: function ( v ) { - - return this.x * v.x + this.y * v.y; - - }, - - lengthSq: function () { - - return this.x * this.x + this.y * this.y; - - }, - - length: function () { - - return Math.sqrt( this.x * this.x + this.y * this.y ); - - }, - - normalize: function () { - - return this.divideScalar( this.length() ); - - }, - - distanceTo: function ( v ) { - - return Math.sqrt( this.distanceToSquared( v ) ); - - }, - - distanceToSquared: function ( v ) { - - var dx = this.x - v.x, dy = this.y - v.y; - return dx * dx + dy * dy; - - }, - - setLength: function ( l ) { - - var oldLength = this.length(); - - if ( oldLength !== 0 && l !== oldLength ) { - - this.multiplyScalar( l / oldLength ); - } - - return this; - - }, - - lerp: function ( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - - return this; - - }, - - equals: function( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) ); - - }, - - fromArray: function ( array ) { - - this.x = array[ 0 ]; - this.y = array[ 1 ]; - - return this; - - }, - - toArray: function () { - - return [ this.x, this.y ]; - - }, - - clone: function () { - - return new THREE.Vector2( this.x, this.y ); - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author *kile / http://kile.stravaganza.org/ - * @author philogb / http://blog.thejit.org/ - * @author mikael emtinger / http://gomo.se/ - * @author egraether / http://egraether.com/ - * @author WestLangley / http://github.com/WestLangley - */ - -THREE.Vector3 = function ( x, y, z ) { - - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - -}; - -THREE.Vector3.prototype = { - - constructor: THREE.Vector3, - - set: function ( x, y, z ) { - - this.x = x; - this.y = y; - this.z = z; - - return this; - - }, - - setX: function ( x ) { - - this.x = x; - - return this; - - }, - - setY: function ( y ) { - - this.y = y; - - return this; - - }, - - setZ: function ( z ) { - - this.z = z; - - return this; - - }, - - setComponent: function ( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - default: return THREE.onerror( 'index is out of range: ' + index ); - - } - - }, - - getComponent: function ( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - default: return THREE.onerror( 'index is out of range: ' + index ); - - } - - }, - - copy: function ( v ) { - - this.x = v.x; - this.y = v.y; - this.z = v.z; - - return this; - - }, - - add: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.onwarning( 'DEPRECATED: Vector3\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); - return this.addVectors( v, w ); - - } - - this.x += v.x; - this.y += v.y; - this.z += v.z; - - return this; - - }, - - addScalar: function ( s ) { - - this.x += s; - this.y += s; - this.z += s; - - return this; - - }, - - addVectors: function ( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - - return this; - - }, - - sub: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.onwarningn( 'DEPRECATED: Vector3\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); - - } - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - - return this; - - }, - - subVectors: function ( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - - return this; - - }, - - multiply: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.onwarning( 'DEPRECATED: Vector3\'s .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); - return this.multiplyVectors( v, w ); - - } - - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; - - return this; - - }, - - multiplyScalar: function ( scalar ) { - - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - - return this; - - }, - - multiplyVectors: function ( a, b ) { - - this.x = a.x * b.x; - this.y = a.y * b.y; - this.z = a.z * b.z; - - return this; - - }, - - applyEuler: function () { - - var quaternion; - - return function ( euler ) { - - if ( ! ( euler instanceof THREE.Euler ) ) return THREE.onerror( 'expecting an Euler', euler ); - - if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); - - this.applyQuaternion( quaternion.setFromEuler( euler ) ); - - return this; - - }; - - }(), - - applyAxisAngle: function () { - - var quaternion; - - return function ( axis, angle ) { - - if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); - - this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); - - return this; - - }; - - }(), - - applyMatrix3: function ( m ) { - - //if ( ! ( m instanceof THREE.Matrix3 ) ) return THREE.onerror( 'expecting an Matrix3', m ); - - var x = this.x; - var y = this.y; - var z = this.z; - - var e = m.elements; - - this.x = e[0] * x + e[3] * y + e[6] * z; - this.y = e[1] * x + e[4] * y + e[7] * z; - this.z = e[2] * x + e[5] * y + e[8] * z; - - return this; - - }, - - applyMatrix4: function ( m ) { - - // input: THREE.Matrix4 affine matrix - //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting an Matrix4', m ); - - var x = this.x, y = this.y, z = this.z; - - var e = m.elements; - - this.x = e[0] * x + e[4] * y + e[8] * z + e[12]; - this.y = e[1] * x + e[5] * y + e[9] * z + e[13]; - this.z = e[2] * x + e[6] * y + e[10] * z + e[14]; - - return this; - - }, - - applyProjection: function ( m ) { - - // input: THREE.Matrix4 projection matrix - //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting an Matrix4', m ); - - var x = this.x, y = this.y, z = this.z; - - var e = m.elements; - var d = 1 / ( e[3] * x + e[7] * y + e[11] * z + e[15] ); // perspective divide - - this.x = ( e[0] * x + e[4] * y + e[8] * z + e[12] ) * d; - this.y = ( e[1] * x + e[5] * y + e[9] * z + e[13] ) * d; - this.z = ( e[2] * x + e[6] * y + e[10] * z + e[14] ) * d; - - return this; - - }, - - applyQuaternion: function ( q ) { - - var x = this.x; - var y = this.y; - var z = this.z; - - var qx = q.x; - var qy = q.y; - var qz = q.z; - var qw = q.w; - - // calculate quat * vector - - var ix = qw * x + qy * z - qz * y; - var iy = qw * y + qz * x - qx * z; - var iz = qw * z + qx * y - qy * x; - var iw = -qx * x - qy * y - qz * z; - - // calculate result * inverse quat - - this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; - this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; - this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; - - return this; - - }, - - transformDirection: function ( m ) { - - // input: THREE.Matrix4 affine matrix - // vector interpreted as a direction - - var x = this.x, y = this.y, z = this.z; - - var e = m.elements; - - this.x = e[0] * x + e[4] * y + e[8] * z; - this.y = e[1] * x + e[5] * y + e[9] * z; - this.z = e[2] * x + e[6] * y + e[10] * z; - - this.normalize(); - - return this; - - }, - - divide: function ( v ) { - - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; - - return this; - - }, - - divideScalar: function ( scalar ) { - - if ( scalar !== 0 ) { - - var invScalar = 1 / scalar; - - this.x *= invScalar; - this.y *= invScalar; - this.z *= invScalar; - - } else { - - this.x = 0; - this.y = 0; - this.z = 0; - - } - - return this; - - }, - - min: function ( v ) { - - if ( this.x > v.x ) { - - this.x = v.x; - - } - - if ( this.y > v.y ) { - - this.y = v.y; - - } - - if ( this.z > v.z ) { - - this.z = v.z; - - } - - return this; - - }, - - max: function ( v ) { - - if ( this.x < v.x ) { - - this.x = v.x; - - } - - if ( this.y < v.y ) { - - this.y = v.y; - - } - - if ( this.z < v.z ) { - - this.z = v.z; - - } - - return this; - - }, - - clamp: function ( min, max ) { - - // This function assumes min < max, if this assumption isn't true it will not operate correctly - - if ( this.x < min.x ) { - - this.x = min.x; - - } else if ( this.x > max.x ) { - - this.x = max.x; - - } - - if ( this.y < min.y ) { - - this.y = min.y; - - } else if ( this.y > max.y ) { - - this.y = max.y; - - } - - if ( this.z < min.z ) { - - this.z = min.z; - - } else if ( this.z > max.z ) { - - this.z = max.z; - - } - - return this; - - }, - - clampScalar: ( function () { - - var min, max; - - return function ( minVal, maxVal ) { - - if ( min === undefined ) { - - min = new THREE.Vector3(); - max = new THREE.Vector3(); - - } - - min.set( minVal, minVal, minVal ); - max.set( maxVal, maxVal, maxVal ); - - return this.clamp( min, max ); - - }; - - } )(), - - floor: function () { - - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); - - return this; - - }, - - ceil: function () { - - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); - - return this; - - }, - - round: function () { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); - - return this; - - }, - - roundToZero: function () { - - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); - - return this; - - }, - - negate: function () { - - return this.multiplyScalar( - 1 ); - - }, - - dot: function ( v ) { - - return this.x * v.x + this.y * v.y + this.z * v.z; - - }, - - lengthSq: function () { - - return this.x * this.x + this.y * this.y + this.z * this.z; - - }, - - length: function () { - - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); - - }, - - lengthManhattan: function () { - - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); - - }, - - normalize: function () { - - return this.divideScalar( this.length() ); - - }, - - setLength: function ( l ) { - - var oldLength = this.length(); - - if ( oldLength !== 0 && l !== oldLength ) { - - this.multiplyScalar( l / oldLength ); - } - - return this; - - }, - - lerp: function ( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - - return this; - - }, - - cross: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.onwarning( 'DEPRECATED: Vector3\'s .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); - return this.crossVectors( v, w ); - - } - - var x = this.x, y = this.y, z = this.z; - - this.x = y * v.z - z * v.y; - this.y = z * v.x - x * v.z; - this.z = x * v.y - y * v.x; - - return this; - - }, - - crossVectors: function ( a, b ) { - - var ax = a.x, ay = a.y, az = a.z; - var bx = b.x, by = b.y, bz = b.z; - - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; - - return this; - - }, - - projectOnVector: function () { - - var v1, dot; - - return function ( vector ) { - - if ( v1 === undefined ) v1 = new THREE.Vector3(); - - v1.copy( vector ).normalize(); - - dot = this.dot( v1 ); - - return this.copy( v1 ).multiplyScalar( dot ); - - }; - - }(), - - projectOnPlane: function () { - - var v1; - - return function ( planeNormal ) { - - if ( v1 === undefined ) v1 = new THREE.Vector3(); - - v1.copy( this ).projectOnVector( planeNormal ); - - return this.sub( v1 ); - - } - - }(), - - reflect: function () { - - // reflect incident vector off plane orthogonal to normal - // normal is assumed to have unit length - - var v1; - - return function ( normal ) { - - if ( v1 === undefined ) v1 = new THREE.Vector3(); - - return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); - - } - - }(), - - angleTo: function ( v ) { - - var theta = this.dot( v ) / ( this.length() * v.length() ); - - // clamp, to handle numerical problems - - return Math.acos( THREE.Math.clamp( theta, -1, 1 ) ); - - }, - - distanceTo: function ( v ) { - - return Math.sqrt( this.distanceToSquared( v ) ); - - }, - - distanceToSquared: function ( v ) { - - var dx = this.x - v.x; - var dy = this.y - v.y; - var dz = this.z - v.z; - - return dx * dx + dy * dy + dz * dz; - - }, - - setEulerFromRotationMatrix: function ( m, order ) { - - THREE.onerror( "REMOVED: Vector3\'s setEulerFromRotationMatrix has been removed in favor of Euler.setFromRotationMatrix(), please update your code."); - - }, - - setEulerFromQuaternion: function ( q, order ) { - - THREE.onerror( "REMOVED: Vector3\'s setEulerFromQuaternion: has been removed in favor of Euler.setFromQuaternion(), please update your code."); - - }, - - getPositionFromMatrix: function ( m ) { - - THREE.onwarning( "DEPRECATED: Vector3\'s .getPositionFromMatrix() has been renamed to .setFromMatrixPosition(). Please update your code." ); - - return this.setFromMatrixPosition( m ); - - }, - - getScaleFromMatrix: function ( m ) { - - THREE.onwarning( "DEPRECATED: Vector3\'s .getScaleFromMatrix() has been renamed to .setFromMatrixScale(). Please update your code." ); - - return this.setFromMatrixScale( m ); - }, - - getColumnFromMatrix: function ( index, matrix ) { - - THREE.onwarning( "DEPRECATED: Vector3\'s .getColumnFromMatrix() has been renamed to .setFromMatrixColumn(). Please update your code." ); - - return this.setFromMatrixColumn( index, matrix ); - - }, - - setFromMatrixPosition: function ( m ) { - - this.x = m.elements[ 12 ]; - this.y = m.elements[ 13 ]; - this.z = m.elements[ 14 ]; - - return this; - - }, - - setFromMatrixScale: function ( m ) { - - var sx = this.set( m.elements[ 0 ], m.elements[ 1 ], m.elements[ 2 ] ).length(); - var sy = this.set( m.elements[ 4 ], m.elements[ 5 ], m.elements[ 6 ] ).length(); - var sz = this.set( m.elements[ 8 ], m.elements[ 9 ], m.elements[ 10 ] ).length(); - - this.x = sx; - this.y = sy; - this.z = sz; - - return this; - }, - - setFromMatrixColumn: function ( index, matrix ) { - - var offset = index * 4; - - var me = matrix.elements; - - this.x = me[ offset ]; - this.y = me[ offset + 1 ]; - this.z = me[ offset + 2 ]; - - return this; - - }, - - equals: function ( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); - - }, - - fromArray: function ( array ) { - - this.x = array[ 0 ]; - this.y = array[ 1 ]; - this.z = array[ 2 ]; - - return this; - - }, - - toArray: function () { - - return [ this.x, this.y, this.z ]; - - }, - - clone: function () { - - return new THREE.Vector3( this.x, this.y, this.z ); - - } - -}; -/** - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author philogb / http://blog.thejit.org/ - * @author mikael emtinger / http://gomo.se/ - * @author egraether / http://egraether.com/ - * @author WestLangley / http://github.com/WestLangley - */ - -THREE.Vector4 = function ( x, y, z, w ) { - - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = ( w !== undefined ) ? w : 1; - -}; - -THREE.Vector4.prototype = { - - constructor: THREE.Vector4, - - set: function ( x, y, z, w ) { - - this.x = x; - this.y = y; - this.z = z; - this.w = w; - - return this; - - }, - - setX: function ( x ) { - - this.x = x; - - return this; - - }, - - setY: function ( y ) { - - this.y = y; - - return this; - - }, - - setZ: function ( z ) { - - this.z = z; - - return this; - - }, - - setW: function ( w ) { - - this.w = w; - - return this; - - }, - - setComponent: function ( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - case 3: this.w = value; break; - default: return THREE.onerror( 'index is out of range: ' + index ); - - } - - }, - - getComponent: function ( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - case 3: return this.w; - default: return THREE.onerror( 'index is out of range: ' + index ); - - } - - }, - - copy: function ( v ) { - - this.x = v.x; - this.y = v.y; - this.z = v.z; - this.w = ( v.w !== undefined ) ? v.w : 1; - - return this; - - }, - - add: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.onwarning( 'DEPRECATED: Vector4\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); - return this.addVectors( v, w ); - - } - - this.x += v.x; - this.y += v.y; - this.z += v.z; - this.w += v.w; - - return this; - - }, - - addScalar: function ( s ) { - - this.x += s; - this.y += s; - this.z += s; - this.w += s; - - return this; - - }, - - addVectors: function ( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - this.w = a.w + b.w; - - return this; - - }, - - sub: function ( v, w ) { - - if ( w !== undefined ) { - - THREE.onwarning( 'DEPRECATED: Vector4\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); - - } - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - this.w -= v.w; - - return this; - - }, - - subVectors: function ( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - this.w = a.w - b.w; - - return this; - - }, - - multiplyScalar: function ( scalar ) { - - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; - - return this; - - }, - - applyMatrix4: function ( m ) { - - //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); - - var x = this.x; - var y = this.y; - var z = this.z; - var w = this.w; - - var e = m.elements; - - this.x = e[0] * x + e[4] * y + e[8] * z + e[12] * w; - this.y = e[1] * x + e[5] * y + e[9] * z + e[13] * w; - this.z = e[2] * x + e[6] * y + e[10] * z + e[14] * w; - this.w = e[3] * x + e[7] * y + e[11] * z + e[15] * w; - - return this; - - }, - - divideScalar: function ( scalar ) { - - if ( scalar !== 0 ) { - - var invScalar = 1 / scalar; - - this.x *= invScalar; - this.y *= invScalar; - this.z *= invScalar; - this.w *= invScalar; - - } else { - - this.x = 0; - this.y = 0; - this.z = 0; - this.w = 1; - - } - - return this; - - }, - - setAxisAngleFromQuaternion: function ( q ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm - - // q is assumed to be normalized - - this.w = 2 * Math.acos( q.w ); - - var s = Math.sqrt( 1 - q.w * q.w ); - - if ( s < 0.0001 ) { - - this.x = 1; - this.y = 0; - this.z = 0; - - } else { - - this.x = q.x / s; - this.y = q.y / s; - this.z = q.z / s; - - } - - return this; - - }, - - setAxisAngleFromRotationMatrix: function ( m ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - var angle, x, y, z, // variables for result - epsilon = 0.01, // margin to allow for rounding errors - epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees - - te = m.elements, - - m11 = te[0], m12 = te[4], m13 = te[8], - m21 = te[1], m22 = te[5], m23 = te[9], - m31 = te[2], m32 = te[6], m33 = te[10]; - - if ( ( Math.abs( m12 - m21 ) < epsilon ) - && ( Math.abs( m13 - m31 ) < epsilon ) - && ( Math.abs( m23 - m32 ) < epsilon ) ) { - - // singularity found - // first check for identity matrix which must have +1 for all terms - // in leading diagonal and zero in other terms - - if ( ( Math.abs( m12 + m21 ) < epsilon2 ) - && ( Math.abs( m13 + m31 ) < epsilon2 ) - && ( Math.abs( m23 + m32 ) < epsilon2 ) - && ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { - - // this singularity is identity matrix so angle = 0 - - this.set( 1, 0, 0, 0 ); - - return this; // zero angle, arbitrary axis - - } - - // otherwise this singularity is angle = 180 - - angle = Math.PI; - - var xx = ( m11 + 1 ) / 2; - var yy = ( m22 + 1 ) / 2; - var zz = ( m33 + 1 ) / 2; - var xy = ( m12 + m21 ) / 4; - var xz = ( m13 + m31 ) / 4; - var yz = ( m23 + m32 ) / 4; - - if ( ( xx > yy ) && ( xx > zz ) ) { // m11 is the largest diagonal term - - if ( xx < epsilon ) { - - x = 0; - y = 0.707106781; - z = 0.707106781; - - } else { - - x = Math.sqrt( xx ); - y = xy / x; - z = xz / x; - - } - - } else if ( yy > zz ) { // m22 is the largest diagonal term - - if ( yy < epsilon ) { - - x = 0.707106781; - y = 0; - z = 0.707106781; - - } else { - - y = Math.sqrt( yy ); - x = xy / y; - z = yz / y; - - } - - } else { // m33 is the largest diagonal term so base result on this - - if ( zz < epsilon ) { - - x = 0.707106781; - y = 0.707106781; - z = 0; - - } else { - - z = Math.sqrt( zz ); - x = xz / z; - y = yz / z; - - } - - } - - this.set( x, y, z, angle ); - - return this; // return 180 deg rotation - - } - - // as we have reached here there are no singularities so we can handle normally - - var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) - + ( m13 - m31 ) * ( m13 - m31 ) - + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize - - if ( Math.abs( s ) < 0.001 ) s = 1; - - // prevent divide by zero, should not happen if matrix is orthogonal and should be - // caught by singularity test above, but I've left it in just in case - - this.x = ( m32 - m23 ) / s; - this.y = ( m13 - m31 ) / s; - this.z = ( m21 - m12 ) / s; - this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); - - return this; - - }, - - min: function ( v ) { - - if ( this.x > v.x ) { - - this.x = v.x; - - } - - if ( this.y > v.y ) { - - this.y = v.y; - - } - - if ( this.z > v.z ) { - - this.z = v.z; - - } - - if ( this.w > v.w ) { - - this.w = v.w; - - } - - return this; - - }, - - max: function ( v ) { - - if ( this.x < v.x ) { - - this.x = v.x; - - } - - if ( this.y < v.y ) { - - this.y = v.y; - - } - - if ( this.z < v.z ) { - - this.z = v.z; - - } - - if ( this.w < v.w ) { - - this.w = v.w; - - } - - return this; - - }, - - clamp: function ( min, max ) { - - // This function assumes min < max, if this assumption isn't true it will not operate correctly - - if ( this.x < min.x ) { - - this.x = min.x; - - } else if ( this.x > max.x ) { - - this.x = max.x; - - } - - if ( this.y < min.y ) { - - this.y = min.y; - - } else if ( this.y > max.y ) { - - this.y = max.y; - - } - - if ( this.z < min.z ) { - - this.z = min.z; - - } else if ( this.z > max.z ) { - - this.z = max.z; - - } - - if ( this.w < min.w ) { - - this.w = min.w; - - } else if ( this.w > max.w ) { - - this.w = max.w; - - } - - return this; - - }, - - clampScalar: ( function () { - - var min, max; - - return function ( minVal, maxVal ) { - - if ( min === undefined ) { - - min = new THREE.Vector4(); - max = new THREE.Vector4(); - - } - - min.set( minVal, minVal, minVal, minVal ); - max.set( maxVal, maxVal, maxVal, maxVal ); - - return this.clamp( min, max ); - - }; - - } )(), - - floor: function () { - - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); - this.w = Math.floor( this.w ); - - return this; - - }, - - ceil: function () { - - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); - this.w = Math.ceil( this.w ); - - return this; - - }, - - round: function () { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); - this.w = Math.round( this.w ); - - return this; - - }, - - roundToZero: function () { - - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); - this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w ); - - return this; - - }, - - negate: function () { - - return this.multiplyScalar( -1 ); - - }, - - dot: function ( v ) { - - return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; - - }, - - lengthSq: function () { - - return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; - - }, - - length: function () { - - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); - - }, - - lengthManhattan: function () { - - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); - - }, - - normalize: function () { - - return this.divideScalar( this.length() ); - - }, - - setLength: function ( l ) { - - var oldLength = this.length(); - - if ( oldLength !== 0 && l !== oldLength ) { - - this.multiplyScalar( l / oldLength ); - - } - - return this; - - }, - - lerp: function ( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - this.w += ( v.w - this.w ) * alpha; - - return this; - - }, - - equals: function ( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); - - }, - - fromArray: function ( array ) { - - this.x = array[ 0 ]; - this.y = array[ 1 ]; - this.z = array[ 2 ]; - this.w = array[ 3 ]; - - return this; - - }, - - toArray: function () { - - return [ this.x, this.y, this.z, this.w ]; - - }, - - clone: function () { - - return new THREE.Vector4( this.x, this.y, this.z, this.w ); - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://exocortex.com - */ - -THREE.Euler = function ( x, y, z, order ) { - - this._x = x || 0; - this._y = y || 0; - this._z = z || 0; - this._order = order || THREE.Euler.DefaultOrder; - -}; - -THREE.Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; - -THREE.Euler.DefaultOrder = 'XYZ'; - -THREE.Euler.prototype = { - - constructor: THREE.Euler, - - _x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder, - - _quaternion: undefined, - - _updateQuaternion: function () { - - if ( this._quaternion !== undefined ) { - - this._quaternion.setFromEuler( this, false ); - - } - - }, - - get x () { - - return this._x; - - }, - - set x ( value ) { - - this._x = value; - this._updateQuaternion(); - - }, - - get y () { - - return this._y; - - }, - - set y ( value ) { - - this._y = value; - this._updateQuaternion(); - - }, - - get z () { - - return this._z; - - }, - - set z ( value ) { - - this._z = value; - this._updateQuaternion(); - - }, - - get order () { - - return this._order; - - }, - - set order ( value ) { - - this._order = value; - this._updateQuaternion(); - - }, - - set: function ( x, y, z, order ) { - - this._x = x; - this._y = y; - this._z = z; - this._order = order || this._order; - - this._updateQuaternion(); - - return this; - - }, - - setFromVector: function ( v, order ) { - - this._x = v.x; - this._y = v.y; - this._z = v.z; - this._order = order || this._order; - - this._updateQuaternion(); - - return this; - - }, - - copy: function ( euler ) { - - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; - - this._updateQuaternion(); - - return this; - - }, - - setFromRotationMatrix: function ( m, order, update ) { - - //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - // clamp, to handle numerical problems - - function clamp( x ) { - - return Math.min( Math.max( x, -1 ), 1 ); - - } - - var te = m.elements; - var m11 = te[0], m12 = te[4], m13 = te[8]; - var m21 = te[1], m22 = te[5], m23 = te[9]; - var m31 = te[2], m32 = te[6], m33 = te[10]; - - order = order || this._order; - - if ( order === 'XYZ' ) { - - this._y = Math.asin( clamp( m13 ) ); - - if ( Math.abs( m13 ) < 0.99999 ) { - - this._x = Math.atan2( - m23, m33 ); - this._z = Math.atan2( - m12, m11 ); - - } else { - - this._x = Math.atan2( m32, m22 ); - this._z = 0; - - } - - } else if ( order === 'YXZ' ) { - - this._x = Math.asin( - clamp( m23 ) ); - - if ( Math.abs( m23 ) < 0.99999 ) { - - this._y = Math.atan2( m13, m33 ); - this._z = Math.atan2( m21, m22 ); - - } else { - - this._y = Math.atan2( - m31, m11 ); - this._z = 0; - - } - - } else if ( order === 'ZXY' ) { - - this._x = Math.asin( clamp( m32 ) ); - - if ( Math.abs( m32 ) < 0.99999 ) { - - this._y = Math.atan2( - m31, m33 ); - this._z = Math.atan2( - m12, m22 ); - - } else { - - this._y = 0; - this._z = Math.atan2( m21, m11 ); - - } - - } else if ( order === 'ZYX' ) { - - this._y = Math.asin( - clamp( m31 ) ); - - if ( Math.abs( m31 ) < 0.99999 ) { - - this._x = Math.atan2( m32, m33 ); - this._z = Math.atan2( m21, m11 ); - - } else { - - this._x = 0; - this._z = Math.atan2( - m12, m22 ); - - } - - } else if ( order === 'YZX' ) { - - this._z = Math.asin( clamp( m21 ) ); - - if ( Math.abs( m21 ) < 0.99999 ) { - - this._x = Math.atan2( - m23, m22 ); - this._y = Math.atan2( - m31, m11 ); - - } else { - - this._x = 0; - this._y = Math.atan2( m13, m33 ); - - } - - } else if ( order === 'XZY' ) { - - this._z = Math.asin( - clamp( m12 ) ); - - if ( Math.abs( m12 ) < 0.99999 ) { - - this._x = Math.atan2( m32, m22 ); - this._y = Math.atan2( m13, m11 ); - - } else { - - this._x = Math.atan2( - m23, m33 ); - this._y = 0; - - } - - } else { - - THREE.onwarning( 'WARNING: Euler.setFromRotationMatrix() given unsupported order: ' + order ) - - } - - this._order = order; - - if ( update !== false ) this._updateQuaternion(); - - return this; - - }, - - setFromQuaternion: function() { - - var mIntermediate = null; - - return function( q, order, update ) { - - mIntermediate = mIntermediate || new THREE.Matrix4(); - mIntermediate.makeRotationFromQuaternion( q ); - this.setFromRotationMatrix( mIntermediate, order, update ); - - return this; - }; - - }(), - - reorder: function () { - - // WARNING: this discards revolution information -bhouston - - var q = new THREE.Quaternion(); - - return function ( newOrder ) { - - q.setFromEuler( this ); - this.setFromQuaternion( q, newOrder ); - - }; - - - }(), - - fromArray: function ( array ) { - - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; - - this._updateQuaternion(); - - return this; - - }, - - toArray: function () { - - return [ this._x, this._y, this._z, this._order ]; - - }, - - equals: function ( euler ) { - - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); - - }, - - - toVector3: function ( optionalResult ) { - - if( optionalResult ) { - return optionalResult.set( this._x, this._y, this._z ); - } - else { - return new THREE.Vector3( this._x, this._y, this._z ); - } - - }, - - clone: function () { - - return new THREE.Euler( this._x, this._y, this._z, this._order ); - - } - -}; - -/** - * @author bhouston / http://exocortex.com - */ - -THREE.Line3 = function ( start, end ) { - - this.start = ( start !== undefined ) ? start : new THREE.Vector3(); - this.end = ( end !== undefined ) ? end : new THREE.Vector3(); - -}; - -THREE.Line3.prototype = { - - constructor: THREE.Line3, - - set: function ( start, end ) { - - this.start.copy( start ); - this.end.copy( end ); - - return this; - - }, - - copy: function ( line ) { - - this.start.copy( line.start ); - this.end.copy( line.end ); - - return this; - - }, - - center: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); - - }, - - delta: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - return result.subVectors( this.end, this.start ); - - }, - - distanceSq: function () { - - return this.start.distanceToSquared( this.end ); - - }, - - distance: function () { - - return this.start.distanceTo( this.end ); - - }, - - at: function ( t, optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - - return this.delta( result ).multiplyScalar( t ).add( this.start ); - - }, - - closestPointToPointParameter: function() { - - var startP = new THREE.Vector3(); - var startEnd = new THREE.Vector3(); - - return function ( point, clampToLine ) { - - startP.subVectors( point, this.start ); - startEnd.subVectors( this.end, this.start ); - - var startEnd2 = startEnd.dot( startEnd ); - var startEnd_startP = startEnd.dot( startP ); - - var t = startEnd_startP / startEnd2; - - if ( clampToLine ) { - - t = THREE.Math.clamp( t, 0, 1 ); - - } - - return t; - - }; - - }(), - - closestPointToPoint: function ( point, clampToLine, optionalTarget ) { - - var t = this.closestPointToPointParameter( point, clampToLine ); - - var result = optionalTarget || new THREE.Vector3(); - - return this.delta( result ).multiplyScalar( t ).add( this.start ); - - }, - - applyMatrix4: function ( matrix ) { - - this.start.applyMatrix4( matrix ); - this.end.applyMatrix4( matrix ); - - return this; - - }, - - equals: function ( line ) { - - return line.start.equals( this.start ) && line.end.equals( this.end ); - - }, - - clone: function () { - - return new THREE.Line3().copy( this ); - - } - -}; - -/** - * @author bhouston / http://exocortex.com - */ - -THREE.Box2 = function ( min, max ) { - - this.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity ); - this.max = ( max !== undefined ) ? max : new THREE.Vector2( -Infinity, -Infinity ); - -}; - -THREE.Box2.prototype = { - - constructor: THREE.Box2, - - set: function ( min, max ) { - - this.min.copy( min ); - this.max.copy( max ); - - return this; - - }, - - setFromPoints: function ( points ) { - - if ( points.length > 0 ) { - - var point = points[ 0 ]; - - this.min.copy( point ); - this.max.copy( point ); - - for ( var i = 1, il = points.length; i < il; i ++ ) { - - point = points[ i ]; - - if ( point.x < this.min.x ) { - - this.min.x = point.x; - - } else if ( point.x > this.max.x ) { - - this.max.x = point.x; - - } - - if ( point.y < this.min.y ) { - - this.min.y = point.y; - - } else if ( point.y > this.max.y ) { - - this.max.y = point.y; - - } - - } - - } else { - - this.makeEmpty(); - - } - - return this; - - }, - - setFromCenterAndSize: function () { - - var v1 = new THREE.Vector2(); - - return function ( center, size ) { - - var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); - - return this; - - }; - - }(), - - copy: function ( box ) { - - this.min.copy( box.min ); - this.max.copy( box.max ); - - return this; - - }, - - makeEmpty: function () { - - this.min.x = this.min.y = Infinity; - this.max.x = this.max.y = -Infinity; - - return this; - - }, - - empty: function () { - - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); - - }, - - center: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector2(); - return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - - }, - - size: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector2(); - return result.subVectors( this.max, this.min ); - - }, - - expandByPoint: function ( point ) { - - this.min.min( point ); - this.max.max( point ); - - return this; - }, - - expandByVector: function ( vector ) { - - this.min.sub( vector ); - this.max.add( vector ); - - return this; - }, - - expandByScalar: function ( scalar ) { - - this.min.addScalar( -scalar ); - this.max.addScalar( scalar ); - - return this; - }, - - containsPoint: function ( point ) { - - if ( point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y ) { - - return false; - - } - - return true; - - }, - - containsBox: function ( box ) { - - if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && - ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) { - - return true; - - } - - return false; - - }, - - getParameter: function ( point, optionalTarget ) { - - // This can potentially have a divide by zero if the box - // has a size dimension of 0. - - var result = optionalTarget || new THREE.Vector2(); - - return result.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ) - ); - - }, - - isIntersectionBox: function ( box ) { - - // using 6 splitting planes to rule out intersections. - - if ( box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y ) { - - return false; - - } - - return true; - - }, - - clampPoint: function ( point, optionalTarget ) { - - var result = optionalTarget || new THREE.Vector2(); - return result.copy( point ).clamp( this.min, this.max ); - - }, - - distanceToPoint: function () { - - var v1 = new THREE.Vector2(); - - return function ( point ) { - - var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); - return clampedPoint.sub( point ).length(); - - }; - - }(), - - intersect: function ( box ) { - - this.min.max( box.min ); - this.max.min( box.max ); - - return this; - - }, - - union: function ( box ) { - - this.min.min( box.min ); - this.max.max( box.max ); - - return this; - - }, - - translate: function ( offset ) { - - this.min.add( offset ); - this.max.add( offset ); - - return this; - - }, - - equals: function ( box ) { - - return box.min.equals( this.min ) && box.max.equals( this.max ); - - }, - - clone: function () { - - return new THREE.Box2().copy( this ); - - } - -}; - -/** - * @author bhouston / http://exocortex.com - * @author WestLangley / http://github.com/WestLangley - */ - -THREE.Box3 = function ( min, max ) { - - this.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity ); - this.max = ( max !== undefined ) ? max : new THREE.Vector3( -Infinity, -Infinity, -Infinity ); - -}; - -THREE.Box3.prototype = { - - constructor: THREE.Box3, - - set: function ( min, max ) { - - this.min.copy( min ); - this.max.copy( max ); - - return this; - - }, - - addPoint: function ( point ) { - - if ( point.x < this.min.x ) { - - this.min.x = point.x; - - } else if ( point.x > this.max.x ) { - - this.max.x = point.x; - - } - - if ( point.y < this.min.y ) { - - this.min.y = point.y; - - } else if ( point.y > this.max.y ) { - - this.max.y = point.y; - - } - - if ( point.z < this.min.z ) { - - this.min.z = point.z; - - } else if ( point.z > this.max.z ) { - - this.max.z = point.z; - - } - - }, - - setFromPoints: function ( points ) { - - if ( points.length > 0 ) { - - var point = points[ 0 ]; - - this.min.copy( point ); - this.max.copy( point ); - - for ( var i = 1, il = points.length; i < il; i ++ ) { - - this.addPoint( points[ i ] ) - - } - - } else { - - this.makeEmpty(); - - } - - return this; - - }, - - setFromCenterAndSize: function() { - - var v1 = new THREE.Vector3(); - - return function ( center, size ) { - - var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); - - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); - - return this; - - }; - - }(), - - setFromObject: function() { - - // Computes the world-axis-aligned bounding box of an object (including its children), - // accounting for both the object's, and childrens', world transforms - - var v1 = new THREE.Vector3(); - - return function( object ) { - - var scope = this; - - object.updateMatrixWorld( true ); - - this.makeEmpty(); - - object.traverse( function ( node ) { - - if ( node.geometry !== undefined && node.geometry.vertices !== undefined ) { - - var vertices = node.geometry.vertices; - - for ( var i = 0, il = vertices.length; i < il; i++ ) { - - v1.copy( vertices[ i ] ); - - v1.applyMatrix4( node.matrixWorld ); - - scope.expandByPoint( v1 ); - - } - - } - - } ); - - return this; - - }; - - }(), - - copy: function ( box ) { - - this.min.copy( box.min ); - this.max.copy( box.max ); - - return this; - - }, - - makeEmpty: function () { - - this.min.x = this.min.y = this.min.z = Infinity; - this.max.x = this.max.y = this.max.z = -Infinity; - - return this; - - }, - - empty: function () { - - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); - - }, - - center: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - - }, - - size: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - return result.subVectors( this.max, this.min ); - - }, - - expandByPoint: function ( point ) { - - this.min.min( point ); - this.max.max( point ); - - return this; - - }, - - expandByVector: function ( vector ) { - - this.min.sub( vector ); - this.max.add( vector ); - - return this; - - }, - - expandByScalar: function ( scalar ) { - - this.min.addScalar( -scalar ); - this.max.addScalar( scalar ); - - return this; - - }, - - containsPoint: function ( point ) { - - if ( point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y || - point.z < this.min.z || point.z > this.max.z ) { - - return false; - - } - - return true; - - }, - - containsBox: function ( box ) { - - if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && - ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) && - ( this.min.z <= box.min.z ) && ( box.max.z <= this.max.z ) ) { - - return true; - - } - - return false; - - }, - - getParameter: function ( point, optionalTarget ) { - - // This can potentially have a divide by zero if the box - // has a size dimension of 0. - - var result = optionalTarget || new THREE.Vector3(); - - return result.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ), - ( point.z - this.min.z ) / ( this.max.z - this.min.z ) - ); - - }, - - isIntersectionBox: function ( box ) { - - // using 6 splitting planes to rule out intersections. - - if ( box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y || - box.max.z < this.min.z || box.min.z > this.max.z ) { - - return false; - - } - - return true; - - }, - - clampPoint: function ( point, optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - return result.copy( point ).clamp( this.min, this.max ); - - }, - - distanceToPoint: function() { - - var v1 = new THREE.Vector3(); - - return function ( point ) { - - var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); - return clampedPoint.sub( point ).length(); - - }; - - }(), - - getBoundingSphere: function() { - - var v1 = new THREE.Vector3(); - - return function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Sphere(); - - result.center = this.center(); - result.radius = this.size( v1 ).length() * 0.5; - - return result; - - }; - - }(), - - intersect: function ( box ) { - - this.min.max( box.min ); - this.max.min( box.max ); - - return this; - - }, - - union: function ( box ) { - - this.min.min( box.min ); - this.max.max( box.max ); - - return this; - - }, - - applyMatrix4: function() { - - var points = [ - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3(), - new THREE.Vector3() - ]; - - return function ( matrix ) { - - // NOTE: I am using a binary pattern to specify all 2^3 combinations below - points[0].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 - points[1].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 - points[2].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 - points[3].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 - points[4].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 - points[5].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 - points[6].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 - points[7].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 - - this.makeEmpty(); - this.setFromPoints( points ); - - return this; - - }; - - }(), - - translate: function ( offset ) { - - this.min.add( offset ); - this.max.add( offset ); - - return this; - - }, - - equals: function ( box ) { - - return box.min.equals( this.min ) && box.max.equals( this.max ); - - }, - - clone: function () { - - return new THREE.Box3().copy( this ); - - } - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://exocortex.com - */ - -THREE.Matrix3 = function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { - - this.elements = new Float32Array(9); - - this.set( - - ( n11 !== undefined ) ? n11 : 1, n12 || 0, n13 || 0, - n21 || 0, ( n22 !== undefined ) ? n22 : 1, n23 || 0, - n31 || 0, n32 || 0, ( n33 !== undefined ) ? n33 : 1 - - ); -}; - -THREE.Matrix3.prototype = { - - constructor: THREE.Matrix3, - - set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { - - var te = this.elements; - - te[0] = n11; te[3] = n12; te[6] = n13; - te[1] = n21; te[4] = n22; te[7] = n23; - te[2] = n31; te[5] = n32; te[8] = n33; - - return this; - - }, - - identity: function () { - - this.set( - - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 - - ); - - return this; - - }, - - copy: function ( m ) { - - var me = m.elements; - - this.set( - - me[0], me[3], me[6], - me[1], me[4], me[7], - me[2], me[5], me[8] - - ); - - return this; - - }, - - multiplyVector3: function ( vector ) { - - THREE.onwarning( 'DEPRECATED: Matrix3\'s .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); - return vector.applyMatrix3( this ); - - }, - - multiplyVector3Array: function() { - - var v1 = new THREE.Vector3(); - - return function ( a ) { - - for ( var i = 0, il = a.length; i < il; i += 3 ) { - - v1.x = a[ i ]; - v1.y = a[ i + 1 ]; - v1.z = a[ i + 2 ]; - - v1.applyMatrix3(this); - - a[ i ] = v1.x; - a[ i + 1 ] = v1.y; - a[ i + 2 ] = v1.z; - - } - - return a; - - }; - - }(), - - multiplyScalar: function ( s ) { - - var te = this.elements; - - te[0] *= s; te[3] *= s; te[6] *= s; - te[1] *= s; te[4] *= s; te[7] *= s; - te[2] *= s; te[5] *= s; te[8] *= s; - - return this; - - }, - - determinant: function () { - - var te = this.elements; - - var a = te[0], b = te[1], c = te[2], - d = te[3], e = te[4], f = te[5], - g = te[6], h = te[7], i = te[8]; - - return a*e*i - a*f*h - b*d*i + b*f*g + c*d*h - c*e*g; - - }, - - getInverse: function ( matrix, errorOnInvertible ) { - - if ( ! ( matrix instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', matrix ); - // ( based on http://code.google.com/p/webgl-mjs/ ) - - var me = matrix.elements; - var te = this.elements; - - te[ 0 ] = me[10] * me[5] - me[6] * me[9]; - te[ 1 ] = - me[10] * me[1] + me[2] * me[9]; - te[ 2 ] = me[6] * me[1] - me[2] * me[5]; - te[ 3 ] = - me[10] * me[4] + me[6] * me[8]; - te[ 4 ] = me[10] * me[0] - me[2] * me[8]; - te[ 5 ] = - me[6] * me[0] + me[2] * me[4]; - te[ 6 ] = me[9] * me[4] - me[5] * me[8]; - te[ 7 ] = - me[9] * me[0] + me[1] * me[8]; - te[ 8 ] = me[5] * me[0] - me[1] * me[4]; - - var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ]; - - // no inverse - - if ( det === 0 ) { - - if ( errorOnInvertible === true ) { - - return THREE.onerror( "Matrix3.getInverse(): can't invert matrix, determinant is 0", this ); - - } - - this.identity(); - - return this; - - } - - this.multiplyScalar( 1.0 / det ); - - return this; - - }, - - transpose: function () { - - var tmp, m = this.elements; - - tmp = m[1]; m[1] = m[3]; m[3] = tmp; - tmp = m[2]; m[2] = m[6]; m[6] = tmp; - tmp = m[5]; m[5] = m[7]; m[7] = tmp; - - return this; - - }, - - getNormalMatrix: function ( m ) { - - //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); - - this.getInverse( m ).transpose(); - - return this; - - }, - - transposeIntoArray: function ( r ) { - - var m = this.elements; - - r[ 0 ] = m[ 0 ]; - r[ 1 ] = m[ 3 ]; - r[ 2 ] = m[ 6 ]; - r[ 3 ] = m[ 1 ]; - r[ 4 ] = m[ 4 ]; - r[ 5 ] = m[ 7 ]; - r[ 6 ] = m[ 2 ]; - r[ 7 ] = m[ 5 ]; - r[ 8 ] = m[ 8 ]; - - return this; - - }, - - fromArray: function ( array ) { - - this.elements.set( array ); - - return this; - - }, - - toArray: function () { - - var te = this.elements; - - return [ - te[ 0 ], te[ 1 ], te[ 2 ], - te[ 3 ], te[ 4 ], te[ 5 ], - te[ 6 ], te[ 7 ], te[ 8 ] - ]; - - }, - - clone: function () { - - var te = this.elements; - - return new THREE.Matrix3( - - te[0], te[3], te[6], - te[1], te[4], te[7], - te[2], te[5], te[8] - - ); - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author philogb / http://blog.thejit.org/ - * @author jordi_ros / http://plattsoft.com - * @author D1plo1d / http://github.com/D1plo1d - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author timknip / http://www.floorplanner.com/ - * @author bhouston / http://exocortex.com - * @author WestLangley / http://github.com/WestLangley - */ - - -THREE.Matrix4 = function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - - this.elements = new Float32Array( 16 ); - - // TODO: if n11 is undefined, then just set to identity, otherwise copy all other values into matrix - // we should not support semi specification of Matrix4, it is just weird. - - var te = this.elements; - - te[0] = ( n11 !== undefined ) ? n11 : 1; te[4] = n12 || 0; te[8] = n13 || 0; te[12] = n14 || 0; - te[1] = n21 || 0; te[5] = ( n22 !== undefined ) ? n22 : 1; te[9] = n23 || 0; te[13] = n24 || 0; - te[2] = n31 || 0; te[6] = n32 || 0; te[10] = ( n33 !== undefined ) ? n33 : 1; te[14] = n34 || 0; - te[3] = n41 || 0; te[7] = n42 || 0; te[11] = n43 || 0; te[15] = ( n44 !== undefined ) ? n44 : 1; - -}; - -THREE.Matrix4.prototype = { - - constructor: THREE.Matrix4, - - set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - - var te = this.elements; - - te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14; - te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24; - te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34; - te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44; - - return this; - - }, - - identity: function () { - - this.set( - - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - }, - - copy: function ( m ) { - - this.elements.set( m.elements ); - - return this; - - }, - - extractPosition: function ( m ) { - - THREE.onwarning( 'DEPRECATED: Matrix4\'s .extractPosition() has been renamed to .copyPosition().' ); - return this.copyPosition( m ); - - }, - - copyPosition: function ( m ) { - - var te = this.elements; - var me = m.elements; - - te[12] = me[12]; - te[13] = me[13]; - te[14] = me[14]; - - return this; - - }, - - extractBasis: function ( xAxis, yAxis, zAxis ) { - - var te = this.elements; - - xAxis.set( te[0], te[1], te[2] ); - yAxis.set( te[4], te[5], te[6] ); - zAxis.set( te[8], te[9], te[10] ); - - return this; - - }, - - makeBasis: function ( xAxis, yAxis, zAxis ) { - - this.identity(); - - var te = this.elements; - te.elements[0] = xAxis.x; te.elements[1] = xAxis.y; te.elements[2] = xAxis.z; - te.elements[4] = yAxis.x; te.elements[5] = yAxis.y; te.elements[6] = yAxis.z; - te.elements[8] = zAxis.x; te.elements[9] = zAxis.y; te.elements[10] = zAxis.z; - - return this; - - }, - - extractRotation: function () { - - var v1 = new THREE.Vector3(); - - return function ( m ) { - - var te = this.elements; - var me = m.elements; - - var scaleX = 1 / v1.set( me[0], me[1], me[2] ).length(); - var scaleY = 1 / v1.set( me[4], me[5], me[6] ).length(); - var scaleZ = 1 / v1.set( me[8], me[9], me[10] ).length(); - - te[0] = me[0] * scaleX; - te[1] = me[1] * scaleX; - te[2] = me[2] * scaleX; - - te[4] = me[4] * scaleY; - te[5] = me[5] * scaleY; - te[6] = me[6] * scaleY; - - te[8] = me[8] * scaleZ; - te[9] = me[9] * scaleZ; - te[10] = me[10] * scaleZ; - - return this; - - }; - - }(), - - makeRotationFromEuler: function ( euler ) { - - if ( ! ( euler instanceof THREE.Euler ) ) return THREE.onerror( 'expecting a Euler', euler ); - - var te = this.elements; - - var x = euler.x, y = euler.y, z = euler.z; - var a = Math.cos( x ), b = Math.sin( x ); - var c = Math.cos( y ), d = Math.sin( y ); - var e = Math.cos( z ), f = Math.sin( z ); - - if ( euler.order === 'XYZ' ) { - - var ae = a * e, af = a * f, be = b * e, bf = b * f; - - te[0] = c * e; - te[4] = - c * f; - te[8] = d; - - te[1] = af + be * d; - te[5] = ae - bf * d; - te[9] = - b * c; - - te[2] = bf - ae * d; - te[6] = be + af * d; - te[10] = a * c; - - } else if ( euler.order === 'YXZ' ) { - - var ce = c * e, cf = c * f, de = d * e, df = d * f; - - te[0] = ce + df * b; - te[4] = de * b - cf; - te[8] = a * d; - - te[1] = a * f; - te[5] = a * e; - te[9] = - b; - - te[2] = cf * b - de; - te[6] = df + ce * b; - te[10] = a * c; - - } else if ( euler.order === 'ZXY' ) { - - var ce = c * e, cf = c * f, de = d * e, df = d * f; - - te[0] = ce - df * b; - te[4] = - a * f; - te[8] = de + cf * b; - - te[1] = cf + de * b; - te[5] = a * e; - te[9] = df - ce * b; - - te[2] = - a * d; - te[6] = b; - te[10] = a * c; - - } else if ( euler.order === 'ZYX' ) { - - var ae = a * e, af = a * f, be = b * e, bf = b * f; - - te[0] = c * e; - te[4] = be * d - af; - te[8] = ae * d + bf; - - te[1] = c * f; - te[5] = bf * d + ae; - te[9] = af * d - be; - - te[2] = - d; - te[6] = b * c; - te[10] = a * c; - - } else if ( euler.order === 'YZX' ) { - - var ac = a * c, ad = a * d, bc = b * c, bd = b * d; - - te[0] = c * e; - te[4] = bd - ac * f; - te[8] = bc * f + ad; - - te[1] = f; - te[5] = a * e; - te[9] = - b * e; - - te[2] = - d * e; - te[6] = ad * f + bc; - te[10] = ac - bd * f; - - } else if ( euler.order === 'XZY' ) { - - var ac = a * c, ad = a * d, bc = b * c, bd = b * d; - - te[0] = c * e; - te[4] = - f; - te[8] = d * e; - - te[1] = ac * f + bd; - te[5] = a * e; - te[9] = ad * f - bc; - - te[2] = bc * f - ad; - te[6] = b * e; - te[10] = bd * f + ac; - - } - - // last column - te[3] = 0; - te[7] = 0; - te[11] = 0; - - // bottom row - te[12] = 0; - te[13] = 0; - te[14] = 0; - te[15] = 1; - - return this; - - }, - - setRotationFromQuaternion: function ( q ) { - - THREE.onwarning( 'DEPRECATED: Matrix4\'s .setRotationFromQuaternion() has been deprecated in favor of makeRotationFromQuaternion. Please update your code.' ); - - return this.makeRotationFromQuaternion( q ); - - }, - - makeRotationFromQuaternion: function ( q ) { - - var te = this.elements; - - var x = q.x, y = q.y, z = q.z, w = q.w; - var x2 = x + x, y2 = y + y, z2 = z + z; - var xx = x * x2, xy = x * y2, xz = x * z2; - var yy = y * y2, yz = y * z2, zz = z * z2; - var wx = w * x2, wy = w * y2, wz = w * z2; - - te[0] = 1 - ( yy + zz ); - te[4] = xy - wz; - te[8] = xz + wy; - - te[1] = xy + wz; - te[5] = 1 - ( xx + zz ); - te[9] = yz - wx; - - te[2] = xz - wy; - te[6] = yz + wx; - te[10] = 1 - ( xx + yy ); - - // last column - te[3] = 0; - te[7] = 0; - te[11] = 0; - - // bottom row - te[12] = 0; - te[13] = 0; - te[14] = 0; - te[15] = 1; - - return this; - - }, - - lookAt: function() { - - var x = new THREE.Vector3(); - var y = new THREE.Vector3(); - var z = new THREE.Vector3(); - - return function ( eye, target, up ) { - - var te = this.elements; - - z.subVectors( eye, target ).normalize(); - - if ( z.length() === 0 ) { - - z.z = 1; - - } - - x.crossVectors( up, z ).normalize(); - - if ( x.length() === 0 ) { - - z.x += 0.0001; - x.crossVectors( up, z ).normalize(); - - } - - y.crossVectors( z, x ); - - - te[0] = x.x; te[4] = y.x; te[8] = z.x; - te[1] = x.y; te[5] = y.y; te[9] = z.y; - te[2] = x.z; te[6] = y.z; te[10] = z.z; - - return this; - - }; - - }(), - - multiply: function ( m, n ) { - - if ( n !== undefined ) { - - THREE.onwarning( 'DEPRECATED: Matrix4\'s .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); - return this.multiplyMatrices( m, n ); - - } - - return this.multiplyMatrices( this, m ); - - }, - - multiplyList: function ( listOfMatrices ) { - - for (var i = 0, il = listOfMatrices.length; i < il ; i++) { - this.multiplyMatrices( this, listOfMatrices[ i ] ); - } - - return this; - - }, - - multiplyMatricesList: function ( listOfMatrices ) { - - if( listOfMatrices.length > 0 ) { - - this.copy( listOfMatrices[0] ); - - this.multiplyList( listOfMatrices.slice( 1 ) ); - - } - else { - - this.identity(); - - } - - return this; - - }, - - multiplyMatrices: function ( a, b ) { - - if ( ! ( a instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', a ); - if ( ! ( b instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', b ); - - var ae = a.elements; - var be = b.elements; - var te = this.elements; - - var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12]; - var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13]; - var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14]; - var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15]; - - var b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12]; - var b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13]; - var b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14]; - var b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15]; - - te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; - te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; - te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; - te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; - - te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; - te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; - te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; - te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; - - te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; - te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; - te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; - te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; - - te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; - te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; - te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; - te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; - - return this; - - }, - - multiplyToArray: function ( a, b, r ) { - - var te = this.elements; - - this.multiplyMatrices( a, b ); - - r[ 0 ] = te[0]; r[ 1 ] = te[1]; r[ 2 ] = te[2]; r[ 3 ] = te[3]; - r[ 4 ] = te[4]; r[ 5 ] = te[5]; r[ 6 ] = te[6]; r[ 7 ] = te[7]; - r[ 8 ] = te[8]; r[ 9 ] = te[9]; r[ 10 ] = te[10]; r[ 11 ] = te[11]; - r[ 12 ] = te[12]; r[ 13 ] = te[13]; r[ 14 ] = te[14]; r[ 15 ] = te[15]; - - return this; - - }, - - multiplyScalar: function ( s ) { - - var te = this.elements; - - te[0] *= s; te[4] *= s; te[8] *= s; te[12] *= s; - te[1] *= s; te[5] *= s; te[9] *= s; te[13] *= s; - te[2] *= s; te[6] *= s; te[10] *= s; te[14] *= s; - te[3] *= s; te[7] *= s; te[11] *= s; te[15] *= s; - - return this; - - }, - - multiplyVector3: function ( vector ) { - - THREE.onwarning( 'DEPRECATED: Matrix4\'s .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); - return vector.applyProjection( this ); - - }, - - multiplyVector4: function ( vector ) { - - THREE.onwarning( 'DEPRECATED: Matrix4\'s .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); - - }, - - multiplyVector3Array: function() { - - var v1 = new THREE.Vector3(); - - return function ( a ) { - - for ( var i = 0, il = a.length; i < il; i += 3 ) { - - v1.x = a[ i ]; - v1.y = a[ i + 1 ]; - v1.z = a[ i + 2 ]; - - v1.applyProjection( this ); - - a[ i ] = v1.x; - a[ i + 1 ] = v1.y; - a[ i + 2 ] = v1.z; - - } - - return a; - - }; - - }(), - - rotateAxis: function ( v ) { - - THREE.onwarning( 'DEPRECATED: Matrix4\'s .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); - - v.transformDirection( this ); - - }, - - crossVector: function ( vector ) { - - THREE.onwarning( 'DEPRECATED: Matrix4\'s .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); - - }, - - determinant: function () { - - var te = this.elements; - - var n11 = te[0], n12 = te[4], n13 = te[8], n14 = te[12]; - var n21 = te[1], n22 = te[5], n23 = te[9], n24 = te[13]; - var n31 = te[2], n32 = te[6], n33 = te[10], n34 = te[14]; - var n41 = te[3], n42 = te[7], n43 = te[11], n44 = te[15]; - - //TODO: make this more efficient - //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) - - return ( - n41 * ( - +n14 * n23 * n32 - -n13 * n24 * n32 - -n14 * n22 * n33 - +n12 * n24 * n33 - +n13 * n22 * n34 - -n12 * n23 * n34 - ) + - n42 * ( - +n11 * n23 * n34 - -n11 * n24 * n33 - +n14 * n21 * n33 - -n13 * n21 * n34 - +n13 * n24 * n31 - -n14 * n23 * n31 - ) + - n43 * ( - +n11 * n24 * n32 - -n11 * n22 * n34 - -n14 * n21 * n32 - +n12 * n21 * n34 - +n14 * n22 * n31 - -n12 * n24 * n31 - ) + - n44 * ( - -n13 * n22 * n31 - -n11 * n23 * n32 - +n11 * n22 * n33 - +n13 * n21 * n32 - -n12 * n21 * n33 - +n12 * n23 * n31 - ) - - ); - - }, - - transpose: function () { - - var te = this.elements; - var tmp; - - tmp = te[1]; te[1] = te[4]; te[4] = tmp; - tmp = te[2]; te[2] = te[8]; te[8] = tmp; - tmp = te[6]; te[6] = te[9]; te[9] = tmp; - - tmp = te[3]; te[3] = te[12]; te[12] = tmp; - tmp = te[7]; te[7] = te[13]; te[13] = tmp; - tmp = te[11]; te[11] = te[14]; te[14] = tmp; - - return this; - - }, - - flattenToArray: function ( flat ) { - - var te = this.elements; - flat[ 0 ] = te[0]; flat[ 1 ] = te[1]; flat[ 2 ] = te[2]; flat[ 3 ] = te[3]; - flat[ 4 ] = te[4]; flat[ 5 ] = te[5]; flat[ 6 ] = te[6]; flat[ 7 ] = te[7]; - flat[ 8 ] = te[8]; flat[ 9 ] = te[9]; flat[ 10 ] = te[10]; flat[ 11 ] = te[11]; - flat[ 12 ] = te[12]; flat[ 13 ] = te[13]; flat[ 14 ] = te[14]; flat[ 15 ] = te[15]; - - return flat; - - }, - - flattenToArrayOffset: function( flat, offset ) { - - var te = this.elements; - flat[ offset ] = te[0]; - flat[ offset + 1 ] = te[1]; - flat[ offset + 2 ] = te[2]; - flat[ offset + 3 ] = te[3]; - - flat[ offset + 4 ] = te[4]; - flat[ offset + 5 ] = te[5]; - flat[ offset + 6 ] = te[6]; - flat[ offset + 7 ] = te[7]; - - flat[ offset + 8 ] = te[8]; - flat[ offset + 9 ] = te[9]; - flat[ offset + 10 ] = te[10]; - flat[ offset + 11 ] = te[11]; - - flat[ offset + 12 ] = te[12]; - flat[ offset + 13 ] = te[13]; - flat[ offset + 14 ] = te[14]; - flat[ offset + 15 ] = te[15]; - - return flat; - - }, - - getPosition: function() { - - var v1 = new THREE.Vector3(); - - return function () { - - THREE.onwarning( 'DEPRECATED: Matrix4\'s .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); - - var te = this.elements; - return v1.set( te[12], te[13], te[14] ); - - }; - - }(), - - setPosition: function ( v ) { - - var te = this.elements; - - te[12] = v.x; - te[13] = v.y; - te[14] = v.z; - - return this; - - }, - - getInverse: function ( m, errorOnInvertible ) { - - //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); - - // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - var te = this.elements; - var me = m.elements; - - var n11 = me[0], n12 = me[4], n13 = me[8], n14 = me[12]; - var n21 = me[1], n22 = me[5], n23 = me[9], n24 = me[13]; - var n31 = me[2], n32 = me[6], n33 = me[10], n34 = me[14]; - var n41 = me[3], n42 = me[7], n43 = me[11], n44 = me[15]; - - te[0] = n23*n34*n42 - n24*n33*n42 + n24*n32*n43 - n22*n34*n43 - n23*n32*n44 + n22*n33*n44; - te[4] = n14*n33*n42 - n13*n34*n42 - n14*n32*n43 + n12*n34*n43 + n13*n32*n44 - n12*n33*n44; - te[8] = n13*n24*n42 - n14*n23*n42 + n14*n22*n43 - n12*n24*n43 - n13*n22*n44 + n12*n23*n44; - te[12] = n14*n23*n32 - n13*n24*n32 - n14*n22*n33 + n12*n24*n33 + n13*n22*n34 - n12*n23*n34; - te[1] = n24*n33*n41 - n23*n34*n41 - n24*n31*n43 + n21*n34*n43 + n23*n31*n44 - n21*n33*n44; - te[5] = n13*n34*n41 - n14*n33*n41 + n14*n31*n43 - n11*n34*n43 - n13*n31*n44 + n11*n33*n44; - te[9] = n14*n23*n41 - n13*n24*n41 - n14*n21*n43 + n11*n24*n43 + n13*n21*n44 - n11*n23*n44; - te[13] = n13*n24*n31 - n14*n23*n31 + n14*n21*n33 - n11*n24*n33 - n13*n21*n34 + n11*n23*n34; - te[2] = n22*n34*n41 - n24*n32*n41 + n24*n31*n42 - n21*n34*n42 - n22*n31*n44 + n21*n32*n44; - te[6] = n14*n32*n41 - n12*n34*n41 - n14*n31*n42 + n11*n34*n42 + n12*n31*n44 - n11*n32*n44; - te[10] = n12*n24*n41 - n14*n22*n41 + n14*n21*n42 - n11*n24*n42 - n12*n21*n44 + n11*n22*n44; - te[14] = n14*n22*n31 - n12*n24*n31 - n14*n21*n32 + n11*n24*n32 + n12*n21*n34 - n11*n22*n34; - te[3] = n23*n32*n41 - n22*n33*n41 - n23*n31*n42 + n21*n33*n42 + n22*n31*n43 - n21*n32*n43; - te[7] = n12*n33*n41 - n13*n32*n41 + n13*n31*n42 - n11*n33*n42 - n12*n31*n43 + n11*n32*n43; - te[11] = n13*n22*n41 - n12*n23*n41 - n13*n21*n42 + n11*n23*n42 + n12*n21*n43 - n11*n22*n43; - te[15] = n12*n23*n31 - n13*n22*n31 + n13*n21*n32 - n11*n23*n32 - n12*n21*n33 + n11*n22*n33; - - var det = n11 * te[ 0 ] + n21 * te[ 4 ] + n31 * te[ 8 ] + n41 * te[ 12 ]; - - if ( det == 0 ) { - - if ( errorOnInvertible === true ) { - - return THREE.onerror( "Matrix4.getInverse(): can't invert matrix, determinant is 0", this ); - - } - - this.identity(); - - return this; - } - - this.multiplyScalar( 1 / det ); - - return this; - - }, - - translate: function ( v ) { - - THREE.onerror( 'DEPRECATED: Matrix4\'s .translate() has been removed.'); - - }, - - rotateX: function ( angle ) { - - THREE.onerror( 'DEPRECATED: Matrix4\'s .rotateX() has been removed.'); - - }, - - rotateY: function ( angle ) { - - THREE.onerror( 'DEPRECATED: Matrix4\'s .rotateY() has been removed.'); - - }, - - rotateZ: function ( angle ) { - - THREE.onerror( 'DEPRECATED: Matrix4\'s .rotateZ() has been removed.'); - - }, - - rotateByAxis: function ( axis, angle ) { - - THREE.onerror( 'DEPRECATED: Matrix4\'s .rotateByAxis() has been removed.'); - - }, - - scale: function ( v ) { - - var te = this.elements; - var x = v.x, y = v.y, z = v.z; - - te[0] *= x; te[4] *= y; te[8] *= z; - te[1] *= x; te[5] *= y; te[9] *= z; - te[2] *= x; te[6] *= y; te[10] *= z; - te[3] *= x; te[7] *= y; te[11] *= z; - - return this; - - }, - - getMaxScaleOnAxis: function () { - - var te = this.elements; - - var scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2]; - var scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6]; - var scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10]; - - return Math.sqrt( Math.max( scaleXSq, Math.max( scaleYSq, scaleZSq ) ) ); - - }, - - makeTranslation: function ( x, y, z ) { - - this.set( - - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, 1 - - ); - - return this; - - }, - - makeRotationX: function ( theta ) { - - var c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - 1, 0, 0, 0, - 0, c, -s, 0, - 0, s, c, 0, - 0, 0, 0, 1 - - ); - - return this; - - }, - - makeRotationY: function ( theta ) { - - var c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - c, 0, s, 0, - 0, 1, 0, 0, - -s, 0, c, 0, - 0, 0, 0, 1 - - ); - - return this; - - }, - - makeRotationZ: function ( theta ) { - - var c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - c, -s, 0, 0, - s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - }, - - makeRotationAxis: function ( axis, angle ) { - - // Based on http://www.gamedev.net/reference/articles/article1199.asp - - var c = Math.cos( angle ); - var s = Math.sin( angle ); - var t = 1 - c; - var x = axis.x, y = axis.y, z = axis.z; - var tx = t * x, ty = t * y; - - this.set( - - tx * x + c, tx * y - s * z, tx * z + s * y, 0, - tx * y + s * z, ty * y + c, ty * z - s * x, 0, - tx * z - s * y, ty * z + s * x, t * z * z + c, 0, - 0, 0, 0, 1 - - ); - - return this; - - }, - - makeScale: function ( x, y, z ) { - - this.set( - - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - 0, 0, 0, 1 - - ); - - return this; - - }, - - - makeShear: function ( vector3Shear, reverseStyle ) { - - var xy = vector3Shear.x; - var xz = vector3Shear.y; - var yz = vector3Shear.z; - - if ( reverseStyle ) { - - this.set( - 1, 0, 0, 0, - xy, 1, 0, 0, - xz, yz, 1, 0, - 0, 0, 0, 1 - ); - - } else { - // Maya style - this.set( - 1, xy, xz, 0, - 0, 1, yz, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - ); - } - - return this; - - }, - - compose: function ( position, quaternion, scale ) { - - this.makeRotationFromQuaternion( quaternion ); - this.scale( scale ); - this.setPosition( position ); - - return this; - - }, - - decompose: function () { - - var vector = new THREE.Vector3(); - var matrix = new THREE.Matrix4(); - - return function ( position, quaternion, scale ) { - - var te = this.elements; - - var sx = vector.set( te[0], te[1], te[2] ).length(); - var sy = vector.set( te[4], te[5], te[6] ).length(); - var sz = vector.set( te[8], te[9], te[10] ).length(); - - // if determine is negative, we need to invert one scale - var det = this.determinant(); - if( det < 0 ) { - sx = -sx; - } - - position.x = te[12]; - position.y = te[13]; - position.z = te[14]; - - // scale the rotation part - - matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy() - - var invSX = 1 / sx; - var invSY = 1 / sy; - var invSZ = 1 / sz; - - matrix.elements[0] *= invSX; - matrix.elements[1] *= invSX; - matrix.elements[2] *= invSX; - - matrix.elements[4] *= invSY; - matrix.elements[5] *= invSY; - matrix.elements[6] *= invSY; - - matrix.elements[8] *= invSZ; - matrix.elements[9] *= invSZ; - matrix.elements[10] *= invSZ; - - quaternion.setFromRotationMatrix( matrix ); - - scale.x = sx; - scale.y = sy; - scale.z = sz; - - return this; - - }; - - }(), - - makeFrustum: function ( left, right, bottom, top, near, far, filmOffset, filmSize ) { - - var te = this.elements; - var x = 2 * near / ( right - left ); - var y = 2 * near / ( top - bottom ); - - var a = ( right + left ) / ( right - left ); - var b = ( top + bottom ) / ( top - bottom ); - var c = - ( far + near ) / ( far - near ); - var d = - 2 * far * near / ( far - near ); - - te[0] = x; te[4] = 0; te[8] = a; te[12] = 0; - te[1] = 0; te[5] = y; te[9] = b; te[13] = 0; - te[2] = 0; te[6] = 0; te[10] = c; te[14] = d; - te[3] = 0; te[7] = 0; te[11] = - 1; te[15] = 0; - - if( filmOffset && filmSize ) { - // shift principle point, details: http://ksimek.github.io/2013/08/13/intrinsic/ - if( filmSize.x !== 0 ) { - te[8] += 2 * filmOffset.x / filmSize.x; - } - if( filmSize.y !== 0 ) { - te[9] += 2 * filmOffset.y / filmSize.y; - } - } - - return this; - - }, - - makePerspective: function ( fov, aspect, near, far, filmOffset, filmSize ) { - - var ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) ); - var ymin = - ymax; - var xmin = ymin * aspect; - var xmax = ymax * aspect; - - return this.makeFrustum( xmin, xmax, ymin, ymax, near, far, filmOffset, filmSize ); - - }, - - makeOrthographic: function ( left, right, top, bottom, near, far ) { - - var te = this.elements; - var w = right - left; - var h = top - bottom; - var p = far - near; - - var x = ( right + left ) / w; - var y = ( top + bottom ) / h; - var z = ( far + near ) / p; - - te[0] = 2 / w; te[4] = 0; te[8] = 0; te[12] = -x; - te[1] = 0; te[5] = 2 / h; te[9] = 0; te[13] = -y; - te[2] = 0; te[6] = 0; te[10] = -2/p; te[14] = -z; - te[3] = 0; te[7] = 0; te[11] = 0; te[15] = 1; - - return this; - - }, - - fromArray: function ( array ) { - - this.elements.set( array ); - - return this; - - }, - - toArray: function () { - - var te = this.elements; - - return [ - te[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ], - te[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ], - te[ 8 ], te[ 9 ], te[ 10 ], te[ 11 ], - te[ 12 ], te[ 13 ], te[ 14 ], te[ 15 ] - ]; - - }, - - clone: function () { - - var te = this.elements; - - return new THREE.Matrix4( - - te[0], te[4], te[8], te[12], - te[1], te[5], te[9], te[13], - te[2], te[6], te[10], te[14], - te[3], te[7], te[11], te[15] - - ); - - } - -}; - -/** - * @author bhouston / http://exocortex.com - */ - -THREE.Ray = function ( origin, direction ) { - - this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3(); - this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3(); - -}; - -THREE.Ray.prototype = { - - constructor: THREE.Ray, - - set: function ( origin, direction ) { - - this.origin.copy( origin ); - this.direction.copy( direction ); - - return this; - - }, - - copy: function ( ray ) { - - this.origin.copy( ray.origin ); - this.direction.copy( ray.direction ); - - return this; - - }, - - at: function ( t, optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - - return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); - - }, - - recast: function () { - - var v1 = new THREE.Vector3(); - - return function ( t ) { - - this.origin.copy( this.at( t, v1 ) ); - - return this; - - }; - - }(), - - closestPointToPoint: function ( point, optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - result.subVectors( point, this.origin ); - var directionDistance = result.dot( this.direction ); - - if ( directionDistance < 0 ) { - - return result.copy( this.origin ); - - } - - return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - - }, - - distanceToPoint: function () { - - var v1 = new THREE.Vector3(); - - return function ( point ) { - - var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); - - // point behind the ray - - if ( directionDistance < 0 ) { - - return this.origin.distanceTo( point ); - - } - - v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - - return v1.distanceTo( point ); - - }; - - }(), - - distanceSqToSegment: function( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - - // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp - // It returns the min distance between the ray and the segment - // defined by v0 and v1 - // It can also set two optional targets : - // - The closest point on the ray - // - The closest point on the segment - - var segCenter = v0.clone().add( v1 ).multiplyScalar( 0.5 ); - var segDir = v1.clone().sub( v0 ).normalize(); - var segExtent = v0.distanceTo( v1 ) * 0.5; - var diff = this.origin.clone().sub( segCenter ); - var a01 = - this.direction.dot( segDir ); - var b0 = diff.dot( this.direction ); - var b1 = - diff.dot( segDir ); - var c = diff.lengthSq(); - var det = Math.abs( 1 - a01 * a01 ); - var s0, s1, sqrDist, extDet; - - if ( det >= 0 ) { - - // The ray and segment are not parallel. - - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; - - if ( s0 >= 0 ) { - - if ( s1 >= - extDet ) { - - if ( s1 <= extDet ) { - - // region 0 - // Minimum at interior points of ray and segment. - - var invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - - } else { - - // region 1 - - s1 = segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } else { - - // region 5 - - s1 = - segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } else { - - if ( s1 <= - extDet) { - - // region 4 - - s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } else if ( s1 <= extDet ) { - - // region 3 - - s0 = 0; - s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; - - } else { - - // region 2 - - s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } - - } else { - - // Ray and segment are parallel. - - s1 = ( a01 > 0 ) ? - segExtent : segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - if ( optionalPointOnRay ) { - - optionalPointOnRay.copy( this.direction.clone().multiplyScalar( s0 ).add( this.origin ) ); - - } - - if ( optionalPointOnSegment ) { - - optionalPointOnSegment.copy( segDir.clone().multiplyScalar( s1 ).add( segCenter ) ); - - } - - return sqrDist; - - }, - - isIntersectionSphere: function ( sphere ) { - - return this.distanceToPoint( sphere.center ) <= sphere.radius; - - }, - - isIntersectionPlane: function ( plane ) { - - // check if the ray lies on the plane first - - var distToPoint = plane.distanceToPoint( this.origin ); - - if ( distToPoint === 0 ) { - - return true; - - } - - var denominator = plane.normal.dot( this.direction ); - - if ( denominator * distToPoint < 0 ) { - - return true - - } - - // ray origin is behind the plane (and is pointing behind it) - - return false; - - }, - - distanceToPlane: function ( plane ) { - - var denominator = plane.normal.dot( this.direction ); - if ( denominator == 0 ) { - - // line is coplanar, return origin - if( plane.distanceToPoint( this.origin ) == 0 ) { - - return 0; - - } - - // Null is preferable to undefined since undefined means.... it is undefined - - return null; - - } - - var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - - // Return if the ray never intersects the plane - - return t >= 0 ? t : null; - - }, - - intersectPlane: function ( plane, optionalTarget ) { - - var t = this.distanceToPlane( plane ); - - if ( t === null ) { - - return null; - } - - return this.at( t, optionalTarget ); - - }, - - isIntersectionBox: function () { - - var v = new THREE.Vector3(); - - return function ( box ) { - - return this.intersectBox( box, v ) !== null; - - } - - }(), - - intersectBox: function ( box , optionalTarget ) { - - // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ - - var tmin,tmax,tymin,tymax,tzmin,tzmax; - - var invdirx = 1/this.direction.x, - invdiry = 1/this.direction.y, - invdirz = 1/this.direction.z; - - var origin = this.origin; - - if (invdirx >= 0) { - - tmin = (box.min.x - origin.x) * invdirx; - tmax = (box.max.x - origin.x) * invdirx; - - } else { - - tmin = (box.max.x - origin.x) * invdirx; - tmax = (box.min.x - origin.x) * invdirx; - } - - if (invdiry >= 0) { - - tymin = (box.min.y - origin.y) * invdiry; - tymax = (box.max.y - origin.y) * invdiry; - - } else { - - tymin = (box.max.y - origin.y) * invdiry; - tymax = (box.min.y - origin.y) * invdiry; - } - - if ((tmin > tymax) || (tymin > tmax)) return null; - - // These lines also handle the case where tmin or tmax is NaN - // (result of 0 * Infinity). x !== x returns true if x is NaN - - if (tymin > tmin || tmin !== tmin ) tmin = tymin; - - if (tymax < tmax || tmax !== tmax ) tmax = tymax; - - if (invdirz >= 0) { - - tzmin = (box.min.z - origin.z) * invdirz; - tzmax = (box.max.z - origin.z) * invdirz; - - } else { - - tzmin = (box.max.z - origin.z) * invdirz; - tzmax = (box.min.z - origin.z) * invdirz; - } - - if ((tmin > tzmax) || (tzmin > tmax)) return null; - - if (tzmin > tmin || tmin !== tmin ) tmin = tzmin; - - if (tzmax < tmax || tmax !== tmax ) tmax = tzmax; - - //return point closest to the ray (positive side) - - if ( tmax < 0 ) return null; - - return this.at( tmin >= 0 ? tmin : tmax, optionalTarget ); - - }, - - intersectTriangle: function() { - - // Compute the offset origin, edges, and normal. - var diff = new THREE.Vector3(); - var edge1 = new THREE.Vector3(); - var edge2 = new THREE.Vector3(); - var normal = new THREE.Vector3(); - - return function ( a, b, c, backfaceCulling, optionalTarget ) { - - // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp - - edge1.subVectors( b, a ); - edge2.subVectors( c, a ); - normal.crossVectors( edge1, edge2 ); - - // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, - // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by - // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) - // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) - // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) - var DdN = this.direction.dot( normal ); - var sign; - - if ( DdN > 0 ) { - - if ( backfaceCulling ) return null; - sign = 1; - - } else if ( DdN < 0 ) { - - sign = - 1; - DdN = - DdN; - - } else { - - return null; - - } - - diff.subVectors( this.origin, a ); - var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) ); - - // b1 < 0, no intersection - if ( DdQxE2 < 0 ) { - - return null; - - } - - var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) ); - - // b2 < 0, no intersection - if ( DdE1xQ < 0 ) { - - return null; - - } - - // b1+b2 > 1, no intersection - if ( DdQxE2 + DdE1xQ > DdN ) { - - return null; - - } - - // Line intersects triangle, check if ray does. - var QdN = - sign * diff.dot( normal ); - - // t < 0, no intersection - if ( QdN < 0 ) { - - return null; - - } - - // Ray intersects triangle. - return this.at( QdN / DdN, optionalTarget ); - - } - - }(), - - applyMatrix4: function ( matrix4 ) { - - this.direction.add( this.origin ).applyMatrix4( matrix4 ); - this.origin.applyMatrix4( matrix4 ); - this.direction.sub( this.origin ); - this.direction.normalize(); - - return this; - }, - - equals: function ( ray ) { - - return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); - - }, - - clone: function () { - - return new THREE.Ray().copy( this ); - - } - -}; - -/** - * @author bhouston / http://exocortex.com - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Sphere = function ( center, radius ) { - - this.center = ( center !== undefined ) ? center : new THREE.Vector3(); - this.radius = ( radius !== undefined ) ? radius : 0; - -}; - -THREE.Sphere.prototype = { - - constructor: THREE.Sphere, - - set: function ( center, radius ) { - - this.center.copy( center ); - this.radius = radius; - - return this; - }, - - - setFromPoints: function () { - - var box = new THREE.Box3(); - - return function ( points, optionalCenter ) { - - var center = this.center; - - if ( optionalCenter !== undefined ) { - - center.copy( optionalCenter ); - - } else { - - box.setFromPoints( points ).center( center ); - - } - - var maxRadiusSq = 0, cx = center.x, cy = center.y, cz = center.z; - - for ( var i = 0, il = points.length; i < il; i ++ ) { - - var pt = points[ i ]; - var dx = cx - pt.x; - var dy = cy - pt.y; - var dz = cz - pt.z; - - var distanceSquared = dx * dx + dy * dy + dz * dz; - - maxRadiusSq = Math.max( maxRadiusSq, distanceSquared ); - - } - - this.radius = Math.sqrt( maxRadiusSq ); - - return this; - - }; - - }(), - - copy: function ( sphere ) { - - this.center.copy( sphere.center ); - this.radius = sphere.radius; - - return this; - - }, - - empty: function () { - - return ( this.radius <= 0 ); - - }, - - containsPoint: function ( point ) { - - return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); - - }, - - distanceToPoint: function ( point ) { - - return ( point.distanceTo( this.center ) - this.radius ); - - }, - - intersectsSphere: function ( sphere ) { - - var radiusSum = this.radius + sphere.radius; - - return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); - - }, - - clampPoint: function ( point, optionalTarget ) { - - var deltaLengthSq = this.center.distanceToSquared( point ); - - var result = optionalTarget || new THREE.Vector3(); - result.copy( point ); - - if ( deltaLengthSq > ( this.radius * this.radius ) ) { - - result.sub( this.center ).normalize(); - result.multiplyScalar( this.radius ).add( this.center ); - - } - - return result; - - }, - - getBoundingBox: function ( optionalTarget ) { - - var box = optionalTarget || new THREE.Box3(); - - box.set( this.center, this.center ); - box.expandByScalar( this.radius ); - - return box; - - }, - - applyMatrix4: function ( matrix ) { - - this.center.applyMatrix4( matrix ); - this.radius = this.radius * matrix.getMaxScaleOnAxis(); - - return this; - - }, - - translate: function ( offset ) { - - this.center.add( offset ); - - return this; - - }, - - equals: function ( sphere ) { - - return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); - - }, - - clone: function () { - - return new THREE.Sphere().copy( this ); - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author bhouston / http://exocortex.com - */ - -THREE.Frustum = function ( p0, p1, p2, p3, p4, p5 ) { - - this.planes = [ - - ( p0 !== undefined ) ? p0 : new THREE.Plane(), - ( p1 !== undefined ) ? p1 : new THREE.Plane(), - ( p2 !== undefined ) ? p2 : new THREE.Plane(), - ( p3 !== undefined ) ? p3 : new THREE.Plane(), - ( p4 !== undefined ) ? p4 : new THREE.Plane(), - ( p5 !== undefined ) ? p5 : new THREE.Plane() - - ]; - -}; - -THREE.Frustum.prototype = { - - constructor: THREE.Frustum, - - set: function ( p0, p1, p2, p3, p4, p5 ) { - - var planes = this.planes; - - planes[0].copy( p0 ); - planes[1].copy( p1 ); - planes[2].copy( p2 ); - planes[3].copy( p3 ); - planes[4].copy( p4 ); - planes[5].copy( p5 ); - - return this; - - }, - - copy: function ( frustum ) { - - var planes = this.planes; - - for( var i = 0; i < 6; i ++ ) { - - planes[i].copy( frustum.planes[i] ); - - } - - return this; - - }, - - setFromMatrix: function ( m ) { - - var planes = this.planes; - var me = m.elements; - var me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3]; - var me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7]; - var me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11]; - var me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15]; - - planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); - planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); - planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); - planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); - planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); - planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); - - return this; - - }, - - intersectsObject: function () { - - var sphere = new THREE.Sphere(); - - return function ( object ) { - - var geometry = object.geometry; - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( object.matrixWorld ); - - return this.intersectsSphere( sphere ); - - }; - - }(), - - intersectsSphere: function ( sphere ) { - - var planes = this.planes; - var center = sphere.center; - var negRadius = -sphere.radius; - - for ( var i = 0; i < 6; i ++ ) { - - var distance = planes[ i ].distanceToPoint( center ); - - if ( distance < negRadius ) { - - return false; - - } - - } - - return true; - - }, - - intersectsBox : function() { - - var p1 = new THREE.Vector3(), - p2 = new THREE.Vector3(); - - return function( box ) { - - var planes = this.planes; - - for ( var i = 0; i < 6 ; i ++ ) { - - var plane = planes[i]; - - p1.x = plane.normal.x > 0 ? box.min.x : box.max.x; - p2.x = plane.normal.x > 0 ? box.max.x : box.min.x; - p1.y = plane.normal.y > 0 ? box.min.y : box.max.y; - p2.y = plane.normal.y > 0 ? box.max.y : box.min.y; - p1.z = plane.normal.z > 0 ? box.min.z : box.max.z; - p2.z = plane.normal.z > 0 ? box.max.z : box.min.z; - - var d1 = plane.distanceToPoint( p1 ); - var d2 = plane.distanceToPoint( p2 ); - - // if both outside plane, no intersection - - if ( d1 < 0 && d2 < 0 ) { - - return false; - - } - } - - return true; - }; - - }(), - - - containsPoint: function ( point ) { - - var planes = this.planes; - - for ( var i = 0; i < 6; i ++ ) { - - if ( planes[ i ].distanceToPoint( point ) < 0 ) { - - return false; - - } - - } - - return true; - - }, - - clone: function () { - - return new THREE.Frustum().copy( this ); - - } - -}; - -/** - * @author bhouston / http://exocortex.com - */ - -THREE.Plane = function ( normal, constant ) { - - this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 ); - this.constant = ( constant !== undefined ) ? constant : 0; - -}; - -THREE.Plane.prototype = { - - constructor: THREE.Plane, - - set: function ( normal, constant ) { - - this.normal.copy( normal ); - this.constant = constant; - - return this; - - }, - - setComponents: function ( x, y, z, w ) { - - this.normal.set( x, y, z ); - this.constant = w; - - return this; - - }, - - setFromNormalAndCoplanarPoint: function ( normal, point ) { - - this.normal.copy( normal ); - this.constant = - point.dot( this.normal ); // must be this.normal, not normal, as this.normal is normalized - - return this; - - }, - - setFromCoplanarPoints: function() { - - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - - return function ( a, b, c ) { - - var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize(); - - // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? - - this.setFromNormalAndCoplanarPoint( normal, a ); - - return this; - - }; - - }(), - - - copy: function ( plane ) { - - this.normal.copy( plane.normal ); - this.constant = plane.constant; - - return this; - - }, - - normalize: function () { - - // Note: will lead to a divide by zero if the plane is invalid. - - var inverseNormalLength = 1.0 / this.normal.length(); - this.normal.multiplyScalar( inverseNormalLength ); - this.constant *= inverseNormalLength; - - return this; - - }, - - negate: function () { - - this.constant *= -1; - this.normal.negate(); - - return this; - - }, - - distanceToPoint: function ( point ) { - - return this.normal.dot( point ) + this.constant; - - }, - - distanceToSphere: function ( sphere ) { - - return this.distanceToPoint( sphere.center ) - sphere.radius; - - }, - - projectPoint: function ( point, optionalTarget ) { - - return this.orthoPoint( point, optionalTarget ).sub( point ).negate(); - - }, - - orthoPoint: function ( point, optionalTarget ) { - - var perpendicularMagnitude = this.distanceToPoint( point ); - - var result = optionalTarget || new THREE.Vector3(); - return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude ); - - }, - - isIntersectionLine: function ( line ) { - - // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. - - var startSign = this.distanceToPoint( line.start ); - var endSign = this.distanceToPoint( line.end ); - - return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); - - }, - - intersectLine: function() { - - var v1 = new THREE.Vector3(); - - return function ( line, optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - - var direction = line.delta( v1 ); - - var denominator = this.normal.dot( direction ); - - if ( denominator == 0 ) { - - // line is coplanar, return origin - if( this.distanceToPoint( line.start ) == 0 ) { - - return result.copy( line.start ); - - } - - // Unsure if this is the correct method to handle this case. - return undefined; - - } - - var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; - - if( t < 0 || t > 1 ) { - - return undefined; - - } - - return result.copy( direction ).multiplyScalar( t ).add( line.start ); - - }; - - }(), - - - coplanarPoint: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - return result.copy( this.normal ).multiplyScalar( - this.constant ); - - }, - - applyMatrix4: function() { - - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - var m1 = new THREE.Matrix3(); - - return function ( matrix, optionalNormalMatrix ) { - - if ( ! ( matrix instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', matrix ); - - // compute new normal based on theory here: - // http://www.songho.ca/opengl/gl_normaltransform.html - var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); - var newNormal = v1.copy( this.normal ).applyMatrix3( normalMatrix ); - - var newCoplanarPoint = this.coplanarPoint( v2 ); - newCoplanarPoint.applyMatrix4( matrix ); - - this.setFromNormalAndCoplanarPoint( newNormal, newCoplanarPoint ); - - return this; - - }; - - }(), - - translate: function ( offset ) { - - this.constant = this.constant - offset.dot( this.normal ); - - return this; - - }, - - equals: function ( plane ) { - - return plane.normal.equals( this.normal ) && ( plane.constant == this.constant ); - - }, - - clone: function () { - - return new THREE.Plane().copy( this ); - - } - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Math = { - - PI2: Math.PI * 2, - DegreeToRadiansFactor: Math.PI / 180, - RadianToDegreesFactor: 180 / Math.PI, - - generateUUID: function () { - - // http://www.broofa.com/Tools/Math.uuid.htm - - var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); - var uuid = new Array(36); - var rnd = 0, r; - - return function () { - - for ( var i = 0; i < 36; i ++ ) { - - if ( i == 8 || i == 13 || i == 18 || i == 23 ) { - - uuid[ i ] = '-'; - - } else if ( i == 14 ) { - - uuid[ i ] = '4'; - - } else { - - if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0; - r = rnd & 0xf; - rnd = rnd >> 4; - uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; - - } - } - - return uuid.join(''); - - }; - - }(), - - // Clamp value to range - - clamp: function ( x, a, b ) { - - return ( x < a ) ? a : ( ( x > b ) ? b : x ); - - }, - - // Clamp value to range to range - - mapLinear: function ( x, a1, a2, b1, b2 ) { - - return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); - - }, - - // http://en.wikipedia.org/wiki/Smoothstep - - smoothstep: function ( x, min, max ) { - - if ( x <= min ) return 0; - if ( x >= max ) return 1; - - x = ( x - min )/( max - min ); - - return x*x*(3 - 2*x); - - }, - - smootherstep: function ( x, min, max ) { - - if ( x <= min ) return 0; - if ( x >= max ) return 1; - - x = ( x - min )/( max - min ); - - return x*x*x*(x*(x*6 - 15) + 10); - - }, - - // Random float from <0, 1> with 16 bits of randomness - // (standard Math.random() creates repetitive patterns when applied over larger space) - - random16: function () { - - return ( 65280 * Math.random() + 255 * Math.random() ) / 65535; - - }, - - // Random integer from interval - - randInt: function ( low, high ) { - - return low + Math.floor( Math.random() * ( high - low + 1 ) ); - - }, - - // Random float from interval - - randFloat: function ( low, high ) { - - return low + Math.random() * ( high - low ); - - }, - - // Random float from <-range/2, range/2> interval - - randFloatSpread: function ( range ) { - - return range * ( 0.5 - Math.random() ); - - }, - - sign: function ( x ) { - - return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : 0; - - }, - - degToRad: function ( degrees ) { - - return degrees * this.DegreeToRadiansFactor; - - }, - - radToDeg: function ( radians ) { - - return radians * this.RadianToDegreesFactor; - - }, - - isPowerOfTwo: function ( value ) { - return ( value & ( value - 1 ) ) === 0 && value !== 0; - } - -}; - -/** - * Spline from Tween.js, slightly optimized (and trashed) - * http://sole.github.com/tween.js/examples/05_spline.html - * - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Spline = function ( points ) { - - this.points = points; - - var c = [], v3 = { x: 0, y: 0, z: 0 }, - point, intPoint, weight, w2, w3, - pa, pb, pc, pd; - - this.initFromArray = function( a ) { - - this.points = []; - - for ( var i = 0; i < a.length; i++ ) { - - this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] }; - - } - - }; - - this.getPoint = function ( k ) { - - point = ( this.points.length - 1 ) * k; - intPoint = Math.floor( point ); - weight = point - intPoint; - - c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > this.points.length - 2 ? this.points.length - 1 : intPoint + 1; - c[ 3 ] = intPoint > this.points.length - 3 ? this.points.length - 1 : intPoint + 2; - - pa = this.points[ c[ 0 ] ]; - pb = this.points[ c[ 1 ] ]; - pc = this.points[ c[ 2 ] ]; - pd = this.points[ c[ 3 ] ]; - - w2 = weight * weight; - w3 = weight * w2; - - v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 ); - v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 ); - v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 ); - - return v3; - - }; - - this.getControlPointsArray = function () { - - var i, p, l = this.points.length, - coords = []; - - for ( i = 0; i < l; i ++ ) { - - p = this.points[ i ]; - coords[ i ] = [ p.x, p.y, p.z ]; - - } - - return coords; - - }; - - // approximate length by summing linear segments - - this.getLength = function ( nSubDivisions ) { - - var i, index, nSamples, position, - point = 0, intPoint = 0, oldIntPoint = 0, - oldPosition = new THREE.Vector3(), - tmpVec = new THREE.Vector3(), - chunkLengths = [], - totalLength = 0; - - // first point has 0 length - - chunkLengths[ 0 ] = 0; - - if ( !nSubDivisions ) nSubDivisions = 100; - - nSamples = this.points.length * nSubDivisions; - - oldPosition.copy( this.points[ 0 ] ); - - for ( i = 1; i < nSamples; i ++ ) { - - index = i / nSamples; - - position = this.getPoint( index ); - tmpVec.copy( position ); - - totalLength += tmpVec.distanceTo( oldPosition ); - - oldPosition.copy( position ); - - point = ( this.points.length - 1 ) * index; - intPoint = Math.floor( point ); - - if ( intPoint != oldIntPoint ) { - - chunkLengths[ intPoint ] = totalLength; - oldIntPoint = intPoint; - - } - - } - - // last point ends with total length - - chunkLengths[ chunkLengths.length ] = totalLength; - - return { chunks: chunkLengths, total: totalLength }; - - }; - - this.reparametrizeByArcLength = function ( samplingCoef ) { - - var i, j, - index, indexCurrent, indexNext, - linearDistance, realDistance, - sampling, position, - newpoints = [], - tmpVec = new THREE.Vector3(), - sl = this.getLength(); - - newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() ); - - for ( i = 1; i < this.points.length; i++ ) { - - //tmpVec.copy( this.points[ i - 1 ] ); - //linearDistance = tmpVec.distanceTo( this.points[ i ] ); - - realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ]; - - sampling = Math.ceil( samplingCoef * realDistance / sl.total ); - - indexCurrent = ( i - 1 ) / ( this.points.length - 1 ); - indexNext = i / ( this.points.length - 1 ); - - for ( j = 1; j < sampling - 1; j++ ) { - - index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent ); - - position = this.getPoint( index ); - newpoints.push( tmpVec.copy( position ).clone() ); - - } - - newpoints.push( tmpVec.copy( this.points[ i ] ).clone() ); - - } - - this.points = newpoints; - - }; - - // Catmull-Rom - - function interpolate( p0, p1, p2, p3, t, t2, t3 ) { - - var v0 = ( p2 - p0 ) * 0.5, - v1 = ( p3 - p1 ) * 0.5; - - return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; - - }; - -}; - -/** - * @author bhouston / http://exocortex.com - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Triangle = function ( a, b, c ) { - - this.a = ( a !== undefined ) ? a : new THREE.Vector3(); - this.b = ( b !== undefined ) ? b : new THREE.Vector3(); - this.c = ( c !== undefined ) ? c : new THREE.Vector3(); - -}; - -THREE.Triangle.normal = function() { - - var v0 = new THREE.Vector3(); - - return function ( a, b, c, optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - - result.subVectors( c, b ); - v0.subVectors( a, b ); - result.cross( v0 ); - - var resultLengthSq = result.lengthSq(); - if( resultLengthSq > 0 ) { - - return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); - - } - - return result.set( 0, 0, 0 ); - - }; - -}(); - -// static/instance method to calculate barycoordinates -// based on: http://www.blackpawn.com/texts/pointinpoly/default.html -THREE.Triangle.barycoordFromPoint = function() { - - var v0 = new THREE.Vector3(); - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - - return function ( point, a, b, c, optionalTarget ) { - - v0.subVectors( c, a ); - v1.subVectors( b, a ); - v2.subVectors( point, a ); - - var dot00 = v0.dot( v0 ); - var dot01 = v0.dot( v1 ); - var dot02 = v0.dot( v2 ); - var dot11 = v1.dot( v1 ); - var dot12 = v1.dot( v2 ); - - var denom = ( dot00 * dot11 - dot01 * dot01 ); - - var result = optionalTarget || new THREE.Vector3(); - - // colinear or singular triangle - if( denom == 0 ) { - // arbitrary location outside of triangle? - // not sure if this is the best idea, maybe should be returning undefined - return result.set( -2, -1, -1 ); - } - - var invDenom = 1 / denom; - var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; - var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; - - // barycoordinates must always sum to 1 - return result.set( 1 - u - v, v, u ); - - }; - -}(); - -THREE.Triangle.containsPoint = function() { - - var v1 = new THREE.Vector3(); - - return function ( point, a, b, c ) { - - var result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 ); - - return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); - - }; - -}(); - -THREE.Triangle.prototype = { - - constructor: THREE.Triangle, - - set: function ( a, b, c ) { - - this.a.copy( a ); - this.b.copy( b ); - this.c.copy( c ); - - return this; - - }, - - setFromPointsAndIndices: function ( points, i0, i1, i2 ) { - - this.a.copy( points[i0] ); - this.b.copy( points[i1] ); - this.c.copy( points[i2] ); - - return this; - - }, - - copy: function ( triangle ) { - - this.a.copy( triangle.a ); - this.b.copy( triangle.b ); - this.c.copy( triangle.c ); - - return this; - - }, - - area: function() { - - var v0 = new THREE.Vector3(); - var v1 = new THREE.Vector3(); - - return function () { - - v0.subVectors( this.c, this.b ); - v1.subVectors( this.a, this.b ); - - return v0.cross( v1 ).length() * 0.5; - - }; - - }(), - - midpoint: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Vector3(); - return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); - - }, - - normal: function ( optionalTarget ) { - - return THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget ); - - }, - - plane: function ( optionalTarget ) { - - var result = optionalTarget || new THREE.Plane(); - - return result.setFromCoplanarPoints( this.a, this.b, this.c ); - - }, - - barycoordFromPoint: function ( point, optionalTarget ) { - - return THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); - - }, - - containsPoint: function ( point ) { - - return THREE.Triangle.containsPoint( point, this.a, this.b, this.c ); - - }, - - equals: function ( triangle ) { - - return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); - - }, - - clone: function () { - - return new THREE.Triangle().copy( this ); - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Vertex = function ( v ) { - - return THREE.onerror( 'THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.' ); - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.UV = function ( u, v ) { - - THREE.onerror( 'THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.') - return new THREE.Vector2( u, v ); - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Clock = function ( autoStart ) { - - this.autoStart = ( autoStart !== undefined ) ? autoStart : true; - - this.startTime = 0; - this.oldTime = 0; - this.elapsedTime = 0; - - this.running = false; - -}; - -THREE.Clock.prototype = { - - constructor: THREE.Clock, - - start: function () { - - this.startTime = self.performance !== undefined && self.performance.now !== undefined - ? self.performance.now() - : Date.now(); - - this.oldTime = this.startTime; - this.running = true; - }, - - stop: function () { - - this.getElapsedTime(); - this.running = false; - - }, - - getElapsedTime: function () { - - this.getDelta(); - return this.elapsedTime; - - }, - - getDelta: function () { - - var diff = 0; - - if ( this.autoStart && ! this.running ) { - - this.start(); - - } - - if ( this.running ) { - - var newTime = self.performance !== undefined && self.performance.now !== undefined - ? self.performance.now() - : Date.now(); - - diff = 0.001 * ( newTime - this.oldTime ); - this.oldTime = newTime; - - this.elapsedTime += diff; - - } - - return diff; - - } - -}; - -/** - * https://github.com/mrdoob/eventdispatcher.js/ - */ - -THREE.EventDispatcher = function () {} - -THREE.EventDispatcher.prototype = { - - constructor: THREE.EventDispatcher, - - apply: function ( object ) { - - object.addEventListener = THREE.EventDispatcher.prototype.addEventListener; - object.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener; - object.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener; - object.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent; - - }, - - addEventListener: function ( type, listener ) { - - if ( this._listeners === undefined ) this._listeners = {}; - - var listeners = this._listeners; - - if ( listeners[ type ] === undefined ) { - - listeners[ type ] = []; - - } - - if ( listeners[ type ].indexOf( listener ) === - 1 ) { - - listeners[ type ].push( listener ); - - } - - }, - - hasEventListener: function ( type, listener ) { - - if ( this._listeners === undefined ) return false; - - var listeners = this._listeners; - - if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) { - - return true; - - } - - return false; - - }, - - removeEventListener: function ( type, listener ) { - - if ( this._listeners === undefined ) return; - - var listeners = this._listeners; - var listenerArray = listeners[ type ]; - - if ( listenerArray !== undefined ) { - - var index = listenerArray.indexOf( listener ); - - if ( index !== - 1 ) { - - listenerArray.splice( index, 1 ); - - } - - } - - }, - - dispatchEvent: function () { - - var array = []; - - return function ( event ) { - - if ( this._listeners === undefined ) return; - - var listeners = this._listeners; - var listenerArray = listeners[ event.type ]; - - if ( listenerArray !== undefined ) { - - event.target = this; - - var length = listenerArray.length; - - for ( var i = 0; i < length; i ++ ) { - - array[ i ] = listenerArray[ i ]; - - } - - for ( var i = 0; i < length; i ++ ) { - - array[ i ].call( this, event ); - - } - - } - - }; - - }() - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author bhouston / http://exocortex.com/ - * @author stephomi / http://stephaneginier.com/ - */ - -( function ( THREE ) { - - THREE.Raycaster = function ( origin, direction, near, far ) { - - this.ray = new THREE.Ray( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) - - this.near = near || 0; - this.far = far || Infinity; - - }; - - var sphere = new THREE.Sphere(); - var localRay = new THREE.Ray(); - var facePlane = new THREE.Plane(); - var intersectPoint = new THREE.Vector3(); - var matrixPosition = new THREE.Vector3(); - - var inverseMatrix = new THREE.Matrix4(); - - var descSort = function ( a, b ) { - - return a.distance - b.distance; - - }; - - var vA = new THREE.Vector3(); - var vB = new THREE.Vector3(); - var vC = new THREE.Vector3(); - - var intersectObject = function ( object, raycaster, intersects ) { - - if ( object instanceof THREE.Sprite ) { - - matrixPosition.setFromMatrixPosition( object.matrixWorld ); - - var distance = raycaster.ray.distanceToPoint( matrixPosition ); - - if ( distance > object.scale.x ) { - - return intersects; - - } - - intersects.push( { - - distance: distance, - point: object.position, - face: null, - object: object - - } ); - - } else if ( object instanceof THREE.LOD ) { - - matrixPosition.setFromMatrixPosition( object.matrixWorld ); - var distance = raycaster.ray.origin.distanceTo( matrixPosition ); - - intersectObject( object.getObjectForDistance( distance ), raycaster, intersects ); - - } else if ( object instanceof THREE.Mesh ) { - - var geometry = object.geometry; - - // Checking boundingSphere distance to ray - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( object.matrixWorld ); - - if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { - - return intersects; - - } - - // Check boundingBox before continuing - - inverseMatrix.getInverse( object.matrixWorld ); - localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - - if ( geometry.boundingBox !== null ) { - - if ( localRay.isIntersectionBox( geometry.boundingBox ) === false ) { - - return intersects; - - } - - } - - if ( geometry instanceof THREE.BufferGeometry ) { - - var material = object.material; - - if ( material === undefined ) return intersects; - - var attributes = geometry.attributes; - - var a, b, c; - var precision = raycaster.precision; - - if ( attributes.index !== undefined ) { - - var offsets = geometry.offsets; - var indices = attributes.index.array; - var positions = attributes.position.array; - - for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) { - - var start = offsets[ oi ].start; - var count = offsets[ oi ].count; - var index = offsets[ oi ].index; - - for ( var i = start, il = start + count; i < il; i += 3 ) { - - a = index + indices[ i ]; - b = index + indices[ i + 1 ]; - c = index + indices[ i + 2 ]; - - vA.set( - positions[ a * 3 ], - positions[ a * 3 + 1 ], - positions[ a * 3 + 2 ] - ); - vB.set( - positions[ b * 3 ], - positions[ b * 3 + 1 ], - positions[ b * 3 + 2 ] - ); - vC.set( - positions[ c * 3 ], - positions[ c * 3 + 1 ], - positions[ c * 3 + 2 ] - ); - - - if ( material.side === THREE.BackSide ) { - - var intersectionPoint = localRay.intersectTriangle( vC, vB, vA, true ); - - } else { - - var intersectionPoint = localRay.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); - - } - - if ( intersectionPoint === null ) continue; - - intersectionPoint.applyMatrix4( object.matrixWorld ); - - var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); - - if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - point: intersectionPoint, - indices: [a, b, c], - face: null, - faceIndex: null, - object: object - - } ); - - } - - } - - } else { - - var offsets = geometry.offsets; - var positions = attributes.position.array; - - for ( var i = 0, il = attributes.position.array.length; i < il; i += 3 ) { - - a = i; - b = i + 1; - c = i + 2; - - vA.set( - positions[ a * 3 ], - positions[ a * 3 + 1 ], - positions[ a * 3 + 2 ] - ); - vB.set( - positions[ b * 3 ], - positions[ b * 3 + 1 ], - positions[ b * 3 + 2 ] - ); - vC.set( - positions[ c * 3 ], - positions[ c * 3 + 1 ], - positions[ c * 3 + 2 ] - ); - - - if ( material.side === THREE.BackSide ) { - - var intersectionPoint = localRay.intersectTriangle( vC, vB, vA, true ); - - } else { - - var intersectionPoint = localRay.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); - - } - - if ( intersectionPoint === null ) continue; - - intersectionPoint.applyMatrix4( object.matrixWorld ); - - var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); - - if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - point: intersectionPoint, - indices: [a, b, c], - face: null, - faceIndex: null, - object: object - - } ); - - } - - } - - } else if ( geometry instanceof THREE.Geometry ) { - - var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; - var objectMaterials = isFaceMaterial === true ? object.material.materials : null; - - var a, b, c, d; - var precision = raycaster.precision; - - var vertices = geometry.vertices; - - for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { - - var face = geometry.faces[ f ]; - - var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : object.material; - - if ( material === undefined ) continue; - - a = vertices[ face.a ]; - b = vertices[ face.b ]; - c = vertices[ face.c ]; - - if ( material.morphTargets === true ) { - - var morphTargets = geometry.morphTargets; - var morphInfluences = object.morphTargetInfluences; - - vA.set( 0, 0, 0 ); - vB.set( 0, 0, 0 ); - vC.set( 0, 0, 0 ); - - for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { - - var influence = morphInfluences[ t ]; - - if ( influence === 0 ) continue; - - var targets = morphTargets[ t ].vertices; - - vA.x += ( targets[ face.a ].x - a.x ) * influence; - vA.y += ( targets[ face.a ].y - a.y ) * influence; - vA.z += ( targets[ face.a ].z - a.z ) * influence; - - vB.x += ( targets[ face.b ].x - b.x ) * influence; - vB.y += ( targets[ face.b ].y - b.y ) * influence; - vB.z += ( targets[ face.b ].z - b.z ) * influence; - - vC.x += ( targets[ face.c ].x - c.x ) * influence; - vC.y += ( targets[ face.c ].y - c.y ) * influence; - vC.z += ( targets[ face.c ].z - c.z ) * influence; - - } - - vA.add( a ); - vB.add( b ); - vC.add( c ); - - a = vA; - b = vB; - c = vC; - - } - - if ( material.side === THREE.BackSide ) { - - var intersectionPoint = localRay.intersectTriangle( c, b, a, true ); - - } else { - - var intersectionPoint = localRay.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide ); - - } - - if ( intersectionPoint === null ) continue; - - intersectionPoint.applyMatrix4( object.matrixWorld ); - - var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); - - if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - point: intersectionPoint, - face: face, - faceIndex: f, - object: object - - } ); - - } - - } - - } else if ( object instanceof THREE.Line ) { - - var precision = raycaster.linePrecision; - var precisionSq = precision * precision; - - var geometry = object.geometry; - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - // Checking boundingSphere distance to ray - - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( object.matrixWorld ); - - if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { - - return intersects; - - } - - inverseMatrix.getInverse( object.matrixWorld ); - localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); - - /* if ( geometry instanceof THREE.BufferGeometry ) { - - } else */ if ( geometry instanceof THREE.Geometry ) { - - var vertices = geometry.vertices; - var nbVertices = vertices.length; - var interSegment = new THREE.Vector3(); - var interRay = new THREE.Vector3(); - var step = object.type === THREE.LineStrip ? 1 : 2; - - for ( var i = 0; i < nbVertices - 1; i = i + step ) { - - var distSq = localRay.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); - - if ( distSq > precisionSq ) continue; - - var distance = localRay.origin.distanceTo( interRay ); - - if ( distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( object.matrixWorld ), - face: null, - faceIndex: null, - object: object - - } ); - - } - - } - - } - - }; - - var intersectDescendants = function ( object, raycaster, intersects ) { - - var descendants = object.getDescendants(); - - for ( var i = 0, l = descendants.length; i < l; i ++ ) { - - intersectObject( descendants[ i ], raycaster, intersects ); - - } - }; - - // - - THREE.Raycaster.prototype.precision = 0.0001; - THREE.Raycaster.prototype.linePrecision = 1; - - THREE.Raycaster.prototype.set = function ( origin, direction ) { - - this.ray.set( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) - - }; - - THREE.Raycaster.prototype.intersectObject = function ( object, recursive ) { - - var intersects = []; - - if ( recursive === true ) { - - intersectDescendants( object, this, intersects ); - - } - - intersectObject( object, this, intersects ); - - intersects.sort( descSort ); - - return intersects; - - }; - - THREE.Raycaster.prototype.intersectObjects = function ( objects, recursive ) { - - var intersects = []; - - for ( var i = 0, l = objects.length; i < l; i ++ ) { - - intersectObject( objects[ i ], this, intersects ); - - if ( recursive === true ) { - - intersectDescendants( objects[ i ], this, intersects ); - - } - - } - - intersects.sort( descSort ); - - return intersects; - - }; - -}( THREE ) ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - */ - -THREE.Object3D = function () { - - this.id = THREE.Object3DIdCount ++; - this.uuid = THREE.Math.generateUUID(); - this.className = "Object3D"; - - this.name = ''; - - this.parent = undefined; - this.children = []; - - this.up = new THREE.Vector3( 0, 1, 0 ); - - this.position = new THREE.Vector3(); - this._rotation = new THREE.Euler(); - this._quaternion = new THREE.Quaternion(); - this.scale = new THREE.Vector3( 1, 1, 1 ); - - // keep rotation and quaternion in sync - - this._rotation._quaternion = this.quaternion; - this._quaternion._euler = this.rotation; - - this.renderDepth = null; - - this.rotationAutoUpdate = true; - - this.matrix = new THREE.Matrix4(); - this.matrixWorld = new THREE.Matrix4(); - - this.matrixAutoUpdate = true; - this.matrixWorldNeedsUpdate = true; - - this.visible = true; - - this.castShadow = false; - this.receiveShadow = false; - - this.frustumCulled = true; - - this.userData = {}; - -}; - - -THREE.Object3D.prototype = { - - constructor: THREE.Object3D, - - get rotation () { - return this._rotation; - }, - - set rotation ( value ) { - - this._rotation = value; - this._rotation._quaternion = this._quaternion; - this._quaternion._euler = this._rotation; - this._rotation._updateQuaternion(); - - }, - - get quaternion () { - return this._quaternion; - }, - - set quaternion ( value ) { - - this._quaternion = value; - this._quaternion._euler = this._rotation; - this._rotation._quaternion = this._quaternion; - this._quaternion._updateEuler(); - - }, - - get eulerOrder () { - - THREE.onwarning( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); - - return this.rotation.order; - - }, - - set eulerOrder ( value ) { - - THREE.onwarning( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); - - this.rotation.order = value; - - }, - - get useQuaternion () { - - THREE.onwarning( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); - - }, - - set useQuaternion ( value ) { - - THREE.onwarning( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); - - }, - - applyMatrix: function ( matrix ) { - - this.matrix.multiplyMatrices( matrix, this.matrix ); - - this.matrix.decompose( this.position, this.quaternion, this.scale ); - - }, - - setRotationFromAxisAngle: function ( axis, angle ) { - - // assumes axis is normalized - - this.quaternion.setFromAxisAngle( axis, angle ); - - }, - - setRotationFromEuler: function ( euler ) { - - this.quaternion.setFromEuler( euler, true ); - - }, - - setRotationFromMatrix: function ( m ) { - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - this.quaternion.setFromRotationMatrix( m ); - - }, - - setRotationFromQuaternion: function ( q ) { - - // assumes q is normalized - - this.quaternion.copy( q ); - - }, - - rotateOnAxis: function() { - - // rotate object on axis in object space - // axis is assumed to be normalized - - var q1 = new THREE.Quaternion(); - - return function ( axis, angle ) { - - q1.setFromAxisAngle( axis, angle ); - - this.quaternion.multiply( q1 ); - - return this; - - } - - }(), - - rotateX: function () { - - var v1 = new THREE.Vector3( 1, 0, 0 ); - - return function ( angle ) { - - return this.rotateOnAxis( v1, angle ); - - }; - - }(), - - rotateY: function () { - - var v1 = new THREE.Vector3( 0, 1, 0 ); - - return function ( angle ) { - - return this.rotateOnAxis( v1, angle ); - - }; - - }(), - - rotateZ: function () { - - var v1 = new THREE.Vector3( 0, 0, 1 ); - - return function ( angle ) { - - return this.rotateOnAxis( v1, angle ); - - }; - - }(), - - translateOnAxis: function () { - - // translate object by distance along axis in object space - // axis is assumed to be normalized - - var v1 = new THREE.Vector3(); - - return function ( axis, distance ) { - - v1.copy( axis ); - - v1.applyQuaternion( this.quaternion ); - - this.position.add( v1.multiplyScalar( distance ) ); - - return this; - - } - - }(), - - translate: function ( distance, axis ) { - - THREE.onwarning( 'DEPRECATED: Object3D\'s .translate() has been removed. Use .translateOnAxis( axis, distance ) instead. Note args have been changed.' ); - return this.translateOnAxis( axis, distance ); - - }, - - translateX: function () { - - var v1 = new THREE.Vector3( 1, 0, 0 ); - - return function ( distance ) { - - return this.translateOnAxis( v1, distance ); - - }; - - }(), - - translateY: function () { - - var v1 = new THREE.Vector3( 0, 1, 0 ); - - return function ( distance ) { - - return this.translateOnAxis( v1, distance ); - - }; - - }(), - - translateZ: function () { - - var v1 = new THREE.Vector3( 0, 0, 1 ); - - return function ( distance ) { - - return this.translateOnAxis( v1, distance ); - - }; - - }(), - - localToWorld: function ( vector ) { - - return vector.applyMatrix4( this.matrixWorld ); - - }, - - worldToLocal: function () { - - var m1 = new THREE.Matrix4(); - - return function ( vector ) { - - return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) ); - - }; - - }(), - - lookAt: function () { - - // This routine does not support objects with rotated and/or translated parent(s) - - var m1 = new THREE.Matrix4(); - - return function ( vector ) { - - m1.lookAt( vector, this.position, this.up ); - - this.quaternion.setFromRotationMatrix( m1 ); - - }; - - }(), - - add: function ( object ) { - - if ( object === this ) { - - THREE.onwarning( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' ); - return; - - } - - if ( object instanceof THREE.Object3D ) { - - if ( object.parent !== undefined ) { - - object.parent.remove( object ); - - } - - object.parent = this; - object.dispatchEvent( { type: 'added' } ); - - this.children.push( object ); - - // add to scene - - var scene = this; - - while ( scene.parent !== undefined ) { - - scene = scene.parent; - - } - - if ( scene !== undefined && scene instanceof THREE.Scene ) { - - scene.__addObject( object ); - - } - - } - - }, - - remove: function ( object ) { - - var index = this.children.indexOf( object ); - - if ( index !== - 1 ) { - - object.parent = undefined; - object.dispatchEvent( { type: 'removed' } ); - - this.children.splice( index, 1 ); - - // remove from scene - - var scene = this; - - while ( scene.parent !== undefined ) { - - scene = scene.parent; - - } - - if ( scene !== undefined && scene instanceof THREE.Scene ) { - - scene.__removeObject( object ); - - } - - } - - }, - - traverse: function ( callback ) { - - callback( this ); - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - this.children[ i ].traverse( callback ); - - } - - }, - - getObjectById: function ( id, recursive ) { - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - var child = this.children[ i ]; - - if ( child.id === id ) { - - return child; - - } - - if ( recursive === true ) { - - child = child.getObjectById( id, recursive ); - - if ( child !== undefined ) { - - return child; - - } - - } - - } - - return undefined; - - }, - - getObjectByName: function ( name, recursive ) { - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - var child = this.children[ i ]; - - if ( child.name === name ) { - - return child; - - } - - if ( recursive === true ) { - - child = child.getObjectByName( name, recursive ); - - if ( child !== undefined ) { - - return child; - - } - - } - - } - - return undefined; - - }, - - getChildByName: function ( name, recursive ) { - - THREE.onwarning( 'DEPRECATED: Object3D\'s .getChildByName() has been renamed to .getObjectByName().' ); - return this.getObjectByName( name, recursive ); - - }, - - getDescendants: function ( array ) { - - if ( array === undefined ) array = []; - - Array.prototype.push.apply( array, this.children ); - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - this.children[ i ].getDescendants( array ); - - } - - return array; - - }, - - updateMatrix: function () { - - this.matrix.compose( this.position, this.quaternion, this.scale ); - - this.matrixWorldNeedsUpdate = true; - - }, - - updateMatrixWorld: function ( force ) { - - if ( this.matrixAutoUpdate === true ) this.updateMatrix(); - - if ( this.matrixWorldNeedsUpdate === true || force === true ) { - - if ( this.parent === undefined ) { - - this.matrixWorld.copy( this.matrix ); - - } else { - - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - - } - - this.matrixWorldNeedsUpdate = false; - - force = true; - - } - - // update children - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - this.children[ i ].updateMatrixWorld( force ); - - } - - }, - - clone: function ( object, recursive ) { - - if ( object === undefined ) object = new THREE.Object3D(); - if ( recursive === undefined ) recursive = true; - - object.name = this.name; - - object.up.copy( this.up ); - - object.position.copy( this.position ); - object.quaternion.copy( this.quaternion ); - object.scale.copy( this.scale ); - - object.renderDepth = this.renderDepth; - - object.rotationAutoUpdate = this.rotationAutoUpdate; - - object.matrix.copy( this.matrix ); - object.matrixWorld.copy( this.matrixWorld ); - - object.matrixAutoUpdate = this.matrixAutoUpdate; - object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate; - - object.visible = this.visible; - - object.castShadow = this.castShadow; - object.receiveShadow = this.receiveShadow; - - object.frustumCulled = this.frustumCulled; - - object.userData = JSON.parse( JSON.stringify( this.userData ) ); - - if ( recursive === true ) { - - for ( var i = 0; i < this.children.length; i ++ ) { - - var child = this.children[ i ]; - object.add( child.clone() ); - - } - - } - - return object; - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype ); - -THREE.Object3DIdCount = 0; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author julianwa / https://github.com/julianwa - */ - -THREE.Projector = function () { - - var _object, _objectCount, _objectPool = [], _objectPoolLength = 0, - _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, - _face, _faceCount, _facePool = [], _facePoolLength = 0, - _line, _lineCount, _linePool = [], _linePoolLength = 0, - _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0, - - _renderData = { objects: [], lights: [], elements: [] }, - - _vA = new THREE.Vector3(), - _vB = new THREE.Vector3(), - _vC = new THREE.Vector3(), - - _vector3 = new THREE.Vector3(), - _vector4 = new THREE.Vector4(), - - _clipBox = new THREE.Box3( new THREE.Vector3( -1, -1, -1 ), new THREE.Vector3( 1, 1, 1 ) ), - _boundingBox = new THREE.Box3(), - _points3 = new Array( 3 ), - _points4 = new Array( 4 ), - - _viewMatrix = new THREE.Matrix4(), - _viewProjectionMatrix = new THREE.Matrix4(), - - _modelMatrix, - _modelViewProjectionMatrix = new THREE.Matrix4(), - - _normalMatrix = new THREE.Matrix3(), - - _frustum = new THREE.Frustum(), - - _clippedVertex1PositionScreen = new THREE.Vector4(), - _clippedVertex2PositionScreen = new THREE.Vector4(); - - this.projectVector = function ( vector, camera ) { - - camera.matrixWorldInverse.getInverse( camera.matrixWorld ); - - _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - - return vector.applyProjection( _viewProjectionMatrix ); - - }; - - this.unprojectVector = function () { - - var projectionMatrixInverse = new THREE.Matrix4(); - - return function ( vector, camera ) { - - projectionMatrixInverse.getInverse( camera.projectionMatrix ); - _viewProjectionMatrix.multiplyMatrices( camera.matrixWorld, projectionMatrixInverse ); - - return vector.applyProjection( _viewProjectionMatrix ); - - }; - - }(); - - this.pickingRay = function ( vector, camera ) { - - // set two vectors with opposing z values - vector.z = -1.0; - var end = new THREE.Vector3( vector.x, vector.y, 1.0 ); - - this.unprojectVector( vector, camera ); - this.unprojectVector( end, camera ); - - // find direction from vector to end - end.sub( vector ).normalize(); - - return new THREE.Raycaster( vector, end ); - - }; - - var projectObject = function ( object ) { - - if ( object.visible === false ) return; - - if ( object instanceof THREE.Light ) { - - _renderData.lights.push( object ); - - } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) { - - if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) { - - _object = getNextObjectInPool(); - _object.id = object.id; - _object.object = object; - - if ( object.renderDepth !== null ) { - - _object.z = object.renderDepth; - - } else { - - _vector3.setFromMatrixPosition( object.matrixWorld ); - _vector3.applyProjection( _viewProjectionMatrix ); - _object.z = _vector3.z; - - } - - _renderData.objects.push( _object ); - - } - - } - - for ( var i = 0, l = object.children.length; i < l; i ++ ) { - - projectObject( object.children[ i ] ); - - } - - }; - - var projectGraph = function ( root, sortObjects ) { - - _objectCount = 0; - - _renderData.objects.length = 0; - _renderData.lights.length = 0; - - projectObject( root ); - - if ( sortObjects === true ) { - - _renderData.objects.sort( painterSort ); - - } - - }; - - var RenderList = function () { - - var normals = []; - - var object = null; - var normalMatrix = new THREE.Matrix3(); - - var setObject = function ( value ) { - - object = value; - normalMatrix.getNormalMatrix( object.matrixWorld ); - - normals.length = 0; - - }; - - var projectVertex = function ( vertex ) { - - var position = vertex.position; - var positionWorld = vertex.positionWorld; - var positionScreen = vertex.positionScreen; - - positionWorld.copy( position ).applyMatrix4( _modelMatrix ); - positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix ); - - var invW = 1 / positionScreen.w; - - positionScreen.x *= invW; - positionScreen.y *= invW; - positionScreen.z *= invW; - - vertex.visible = positionScreen.x >= -1 && positionScreen.x <= 1 && - positionScreen.y >= -1 && positionScreen.y <= 1 && - positionScreen.z >= -1 && positionScreen.z <= 1; - - }; - - var pushVertex = function ( x, y, z ) { - - _vertex = getNextVertexInPool(); - _vertex.position.set( x, y, z ); - - projectVertex( _vertex ); - - }; - - var pushNormal = function ( x, y, z ) { - - normals.push( x, y, z ); - - }; - - var checkTriangleVisibility = function ( v1, v2, v3 ) { - - _points3[ 0 ] = v1.positionScreen; - _points3[ 1 ] = v2.positionScreen; - _points3[ 2 ] = v3.positionScreen; - - if ( v1.visible === true || v2.visible === true || v3.visible === true || - _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) ) ) { - - return ( ( v3.positionScreen.x - v1.positionScreen.x ) * - ( v2.positionScreen.y - v1.positionScreen.y ) - - ( v3.positionScreen.y - v1.positionScreen.y ) * - ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0; - - } - - return false; - - }; - - var pushLine = function ( a, b ) { - - var v1 = _vertexPool[ a ]; - var v2 = _vertexPool[ b ]; - - _line = getNextLineInPool(); - - _line.id = object.id; - _line.v1.copy( v1 ); - _line.v2.copy( v2 ); - _line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2; - - _line.material = object.material; - - _renderData.elements.push( _line ); - - }; - - var pushTriangle = function ( a, b, c ) { - - var v1 = _vertexPool[ a ]; - var v2 = _vertexPool[ b ]; - var v3 = _vertexPool[ c ]; - - if ( checkTriangleVisibility( v1, v2, v3 ) === true ) { - - _face = getNextFaceInPool(); - - _face.id = object.id; - _face.v1.copy( v1 ); - _face.v2.copy( v2 ); - _face.v3.copy( v3 ); - _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; - - for ( var i = 0; i < 3; i ++ ) { - - var offset = arguments[ i ] * 3; - var normal = _face.vertexNormalsModel[ i ]; - - normal.set( normals[ offset + 0 ], normals[ offset + 1 ], normals[ offset + 2 ] ); - normal.applyMatrix3( normalMatrix ).normalize(); - - } - - _face.vertexNormalsLength = 3; - - _face.material = object.material; - - _renderData.elements.push( _face ); - - } - - }; - - return { - setObject: setObject, - projectVertex: projectVertex, - checkTriangleVisibility: checkTriangleVisibility, - pushVertex: pushVertex, - pushNormal: pushNormal, - pushLine: pushLine, - pushTriangle: pushTriangle - } - - }; - - var renderList = new RenderList(); - - this.projectScene = function ( scene, camera, sortObjects, sortElements ) { - - var object, geometry, vertices, faces, face, faceVertexNormals, faceVertexUvs, uvs, - isFaceMaterial, objectMaterials; - - _faceCount = 0; - _lineCount = 0; - _spriteCount = 0; - - _renderData.elements.length = 0; - - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - if ( camera.parent === undefined ) camera.updateMatrixWorld(); - - _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) ); - _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix ); - - _frustum.setFromMatrix( _viewProjectionMatrix ); - - projectGraph( scene, sortObjects ); - - for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) { - - object = _renderData.objects[ o ].object; - geometry = object.geometry; - - renderList.setObject( object ); - - _modelMatrix = object.matrixWorld; - - _vertexCount = 0; - - if ( object instanceof THREE.Mesh ) { - - if ( geometry instanceof THREE.BufferGeometry ) { - - var attributes = geometry.attributes; - var offsets = geometry.offsets; - - if ( attributes.position === undefined ) continue; - - var positions = attributes.position.array; - - for ( var i = 0, l = positions.length; i < l; i += 3 ) { - - renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - - } - - var normals = attributes.normal.array; - - for ( var i = 0, l = normals.length; i < l; i += 3 ) { - - renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ); - - } - - if ( attributes.index !== undefined ) { - - var indices = attributes.index.array; - - if ( offsets.length > 0 ) { - - for ( var o = 0; o < offsets.length; o ++ ) { - - var offset = offsets[ o ]; - var index = offset.index; - - for ( var i = offset.start, l = offset.start + offset.count; i < l; i += 3 ) { - - renderList.pushTriangle( indices[ i ] + index, indices[ i + 1 ] + index, indices[ i + 2 ] + index ); - - } - - } - - } else { - - for ( var i = 0, l = indices.length; i < l; i += 3 ) { - - renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); - - } - - } - - } else { - - for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) { - - renderList.pushTriangle( i, i + 1, i + 2 ); - - } - - } - - } else if ( geometry instanceof THREE.Geometry ) { - - vertices = geometry.vertices; - faces = geometry.faces; - faceVertexUvs = geometry.faceVertexUvs; - - _normalMatrix.getNormalMatrix( _modelMatrix ); - - isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; - objectMaterials = isFaceMaterial === true ? object.material : null; - - for ( var v = 0, vl = vertices.length; v < vl; v ++ ) { - - var vertex = vertices[ v ]; - renderList.pushVertex( vertex.x, vertex.y, vertex.z ); - - } - - for ( var f = 0, fl = faces.length; f < fl; f ++ ) { - - face = faces[ f ]; - - var material = isFaceMaterial === true - ? objectMaterials.materials[ face.materialIndex ] - : object.material; - - if ( material === undefined ) continue; - - var side = material.side; - - var v1 = _vertexPool[ face.a ]; - var v2 = _vertexPool[ face.b ]; - var v3 = _vertexPool[ face.c ]; - - if ( material.morphTargets === true ) { - - var morphTargets = geometry.morphTargets; - var morphInfluences = object.morphTargetInfluences; - - var v1p = v1.position; - var v2p = v2.position; - var v3p = v3.position; - - _vA.set( 0, 0, 0 ); - _vB.set( 0, 0, 0 ); - _vC.set( 0, 0, 0 ); - - for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { - - var influence = morphInfluences[ t ]; - - if ( influence === 0 ) continue; - - var targets = morphTargets[ t ].vertices; - - _vA.x += ( targets[ face.a ].x - v1p.x ) * influence; - _vA.y += ( targets[ face.a ].y - v1p.y ) * influence; - _vA.z += ( targets[ face.a ].z - v1p.z ) * influence; - - _vB.x += ( targets[ face.b ].x - v2p.x ) * influence; - _vB.y += ( targets[ face.b ].y - v2p.y ) * influence; - _vB.z += ( targets[ face.b ].z - v2p.z ) * influence; - - _vC.x += ( targets[ face.c ].x - v3p.x ) * influence; - _vC.y += ( targets[ face.c ].y - v3p.y ) * influence; - _vC.z += ( targets[ face.c ].z - v3p.z ) * influence; - - } - - v1.position.add( _vA ); - v2.position.add( _vB ); - v3.position.add( _vC ); - - renderList.projectVertex( v1 ); - renderList.projectVertex( v2 ); - renderList.projectVertex( v3 ); - - } - - var visible = renderList.checkTriangleVisibility( v1, v2, v3 ); - - if ( ( visible === false && side === THREE.FrontSide ) || - ( visible === true && side === THREE.BackSide ) ) continue; - - _face = getNextFaceInPool(); - - _face.id = object.id; - _face.v1.copy( v1 ); - _face.v2.copy( v2 ); - _face.v3.copy( v3 ); - - _face.normalModel.copy( face.normal ); - - if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { - - _face.normalModel.negate(); - - } - - _face.normalModel.applyMatrix3( _normalMatrix ).normalize(); - - _face.centroidModel.copy( face.centroid ).applyMatrix4( _modelMatrix ); - - faceVertexNormals = face.vertexNormals; - - for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) { - - var normalModel = _face.vertexNormalsModel[ n ]; - normalModel.copy( faceVertexNormals[ n ] ); - - if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { - - normalModel.negate(); - - } - - normalModel.applyMatrix3( _normalMatrix ).normalize(); - - } - - _face.vertexNormalsLength = faceVertexNormals.length; - - for ( var c = 0, cl = Math.min( faceVertexUvs.length, 3 ); c < cl; c ++ ) { - - uvs = faceVertexUvs[ c ][ f ]; - - if ( uvs === undefined ) continue; - - for ( var u = 0, ul = uvs.length; u < ul; u ++ ) { - - _face.uvs[ c ][ u ] = uvs[ u ]; - - } - - } - - _face.color = face.color; - _face.material = material; - - _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; - - _renderData.elements.push( _face ); - - } - - } - - } else if ( object instanceof THREE.Line ) { - - if ( geometry instanceof THREE.BufferGeometry ) { - - var attributes = geometry.attributes; - - if ( attributes.position !== undefined ) { - - var positions = attributes.position.array; - - for ( var i = 0, l = positions.length; i < l; i += 3 ) { - - renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - - } - - if ( attributes.index !== undefined ) { - - var indices = attributes.index.array; - - for ( var i = 0, l = indices.length; i < l; i += 2 ) { - - renderList.pushLine( indices[ i ], indices[ i + 1 ] ); - - } - - } else { - - for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i ++ ) { - - renderList.pushLine( i, i + 1 ); - - } - - } - - } - - } else if ( geometry instanceof THREE.Geometry ) { - - _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); - - vertices = object.geometry.vertices; - - if ( vertices.length === 0 ) continue; - - v1 = getNextVertexInPool(); - v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix ); - - // Handle LineStrip and LinePieces - var step = object.type === THREE.LinePieces ? 2 : 1; - - for ( var v = 1, vl = vertices.length; v < vl; v ++ ) { - - v1 = getNextVertexInPool(); - v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix ); - - if ( ( v + 1 ) % step > 0 ) continue; - - v2 = _vertexPool[ _vertexCount - 2 ]; - - _clippedVertex1PositionScreen.copy( v1.positionScreen ); - _clippedVertex2PositionScreen.copy( v2.positionScreen ); - - if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) { - - // Perform the perspective divide - _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w ); - _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w ); - - _line = getNextLineInPool(); - - _line.id = object.id; - _line.v1.positionScreen.copy( _clippedVertex1PositionScreen ); - _line.v2.positionScreen.copy( _clippedVertex2PositionScreen ); - - _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); - - _line.material = object.material; - - if ( object.material.vertexColors === THREE.VertexColors ) { - - _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] ); - _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] ); - - } - - _renderData.elements.push( _line ); - - } - - } - - } - - } else if ( object instanceof THREE.Sprite ) { - - _vector4.set( _modelMatrix.elements[12], _modelMatrix.elements[13], _modelMatrix.elements[14], 1 ); - _vector4.applyMatrix4( _viewProjectionMatrix ); - - var invW = 1 / _vector4.w; - - _vector4.z *= invW; - - if ( _vector4.z >= -1 && _vector4.z <= 1 ) { - - _sprite = getNextSpriteInPool(); - _sprite.id = object.id; - _sprite.x = _vector4.x * invW; - _sprite.y = _vector4.y * invW; - _sprite.z = _vector4.z; - _sprite.object = object; - - _sprite.rotation = object.rotation; - - _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[0] ) / ( _vector4.w + camera.projectionMatrix.elements[12] ) ); - _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[5] ) / ( _vector4.w + camera.projectionMatrix.elements[13] ) ); - - _sprite.material = object.material; - - _renderData.elements.push( _sprite ); - - } - - } - - } - - if ( sortElements === true ) _renderData.elements.sort( painterSort ); - - return _renderData; - - }; - - // Pools - - function getNextObjectInPool() { - - if ( _objectCount === _objectPoolLength ) { - - var object = new THREE.RenderableObject(); - _objectPool.push( object ); - _objectPoolLength ++; - _objectCount ++; - return object; - - } - - return _objectPool[ _objectCount ++ ]; - - } - - function getNextVertexInPool() { - - if ( _vertexCount === _vertexPoolLength ) { - - var vertex = new THREE.RenderableVertex(); - _vertexPool.push( vertex ); - _vertexPoolLength ++; - _vertexCount ++; - return vertex; - - } - - return _vertexPool[ _vertexCount ++ ]; - - } - - function getNextFaceInPool() { - - if ( _faceCount === _facePoolLength ) { - - var face = new THREE.RenderableFace(); - _facePool.push( face ); - _facePoolLength ++; - _faceCount ++; - return face; - - } - - return _facePool[ _faceCount ++ ]; - - - } - - function getNextLineInPool() { - - if ( _lineCount === _linePoolLength ) { - - var line = new THREE.RenderableLine(); - _linePool.push( line ); - _linePoolLength ++; - _lineCount ++ - return line; - - } - - return _linePool[ _lineCount ++ ]; - - } - - function getNextSpriteInPool() { - - if ( _spriteCount === _spritePoolLength ) { - - var sprite = new THREE.RenderableSprite(); - _spritePool.push( sprite ); - _spritePoolLength ++; - _spriteCount ++ - return sprite; - - } - - return _spritePool[ _spriteCount ++ ]; - - } - - // - - function painterSort( a, b ) { - - if ( a.z !== b.z ) { - - return b.z - a.z; - - } else if ( a.id !== b.id ) { - - return a.id - b.id; - - } else { - - return 0; - - } - - } - - function clipLine( s1, s2 ) { - - var alpha1 = 0, alpha2 = 1, - - // Calculate the boundary coordinate of each vertex for the near and far clip planes, - // Z = -1 and Z = +1, respectively. - bc1near = s1.z + s1.w, - bc2near = s2.z + s2.w, - bc1far = - s1.z + s1.w, - bc2far = - s2.z + s2.w; - - if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { - - // Both vertices lie entirely within all clip planes. - return true; - - } else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) { - - // Both vertices lie entirely outside one of the clip planes. - return false; - - } else { - - // The line segment spans at least one clip plane. - - if ( bc1near < 0 ) { - - // v1 lies outside the near plane, v2 inside - alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) ); - - } else if ( bc2near < 0 ) { - - // v2 lies outside the near plane, v1 inside - alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) ); - - } - - if ( bc1far < 0 ) { - - // v1 lies outside the far plane, v2 inside - alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) ); - - } else if ( bc2far < 0 ) { - - // v2 lies outside the far plane, v2 inside - alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) ); - - } - - if ( alpha2 < alpha1 ) { - - // The line segment spans two boundaries, but is outside both of them. - // (This can't happen when we're only clipping against just near/far but good - // to leave the check here for future usage if other clip planes are added.) - return false; - - } else { - - // Update the s1 and s2 vertices to match the clipped line segment. - s1.lerp( s2, alpha1 ); - s2.lerp( s1, 1 - alpha2 ); - - return true; - - } - - } - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) { - - this.a = a; - this.b = b; - this.c = c; - - this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); - this.vertexNormals = normal instanceof Array ? normal : [ ]; - - this.color = color instanceof THREE.Color ? color : new THREE.Color(); - this.vertexColors = color instanceof Array ? color : []; - - this.vertexTangents = []; - - this.materialIndex = materialIndex !== undefined ? materialIndex : 0; - - this.centroid = new THREE.Vector3(); - -}; - -THREE.Face3.prototype = { - - constructor: THREE.Face3, - - clone: function () { - - var face = new THREE.Face3( this.a, this.b, this.c ); - - face.normal.copy( this.normal ); - face.color.copy( this.color ); - face.centroid.copy( this.centroid ); - - face.materialIndex = this.materialIndex; - - var i, il; - for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone(); - for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone(); - for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone(); - - return face; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { - - THREE.onwarning( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.') - - return new THREE.Face3( a, b, c, normal, color, materialIndex ); - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.BufferGeometry = function () { - - this.id = THREE.GeometryIdCount ++; - this.uuid = THREE.Math.generateUUID(); - this.className = "BufferGeometry"; - this.name = ''; - - // attributes - - this.attributes = {}; - - // offsets for chunks when using indexed elements - - this.offsets = []; - - // boundings - - this.boundingBox = null; - this.boundingSphere = null; - -}; - -THREE.BufferGeometry.prototype = { - - constructor: THREE.BufferGeometry, - - addAttribute: function ( name, type, numItems, itemSize ) { - - this.attributes[ name ] = { - - array: new type( numItems * itemSize ), - itemSize: itemSize - - }; - - return this.attributes[ name ]; - - }, - - applyMatrix: function ( matrix ) { - - var position = this.attributes.position; - - if ( position !== undefined ) { - - matrix.multiplyVector3Array( position.array ); - position.needsUpdate = true; - - } - - var normal = this.attributes.normal; - - if ( normal !== undefined ) { - - var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - - normalMatrix.multiplyVector3Array( normal.array ); - normal.needsUpdate = true; - - } - - }, - - computeBoundingBox: function () { - - if ( this.boundingBox === null ) { - - this.boundingBox = new THREE.Box3(); - - } - - var positions = this.attributes[ "position" ].array; - - if ( positions ) { - - var bb = this.boundingBox; - - if( positions.length >= 3 ) { - bb.min.x = bb.max.x = positions[ 0 ]; - bb.min.y = bb.max.y = positions[ 1 ]; - bb.min.z = bb.max.z = positions[ 2 ]; - } - - for ( var i = 3, il = positions.length; i < il; i += 3 ) { - - var x = positions[ i ]; - var y = positions[ i + 1 ]; - var z = positions[ i + 2 ]; - - // bounding box - - if ( x < bb.min.x ) { - - bb.min.x = x; - - } else if ( x > bb.max.x ) { - - bb.max.x = x; - - } - - if ( y < bb.min.y ) { - - bb.min.y = y; - - } else if ( y > bb.max.y ) { - - bb.max.y = y; - - } - - if ( z < bb.min.z ) { - - bb.min.z = z; - - } else if ( z > bb.max.z ) { - - bb.max.z = z; - - } - - } - - } - - if ( positions === undefined || positions.length === 0 ) { - - this.boundingBox.min.set( 0, 0, 0 ); - this.boundingBox.max.set( 0, 0, 0 ); - - } - - }, - - computeBoundingSphere: function () { - - var box = new THREE.Box3(); - var vector = new THREE.Vector3(); - - return function () { - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new THREE.Sphere(); - - } - - var positions = this.attributes[ "position" ].array; - - if ( positions ) { - - box.makeEmpty(); - - var center = this.boundingSphere.center; - - for ( var i = 0, il = positions.length; i < il; i += 3 ) { - - vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - box.addPoint( vector ); - - } - - box.center( center ); - - var maxRadiusSq = 0; - - for ( var i = 0, il = positions.length; i < il; i += 3 ) { - - vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); - - } - - this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - - } - - } - - }(), - - computeVertexNormals: function () { - - if ( this.attributes[ "position" ] ) { - - var i, il; - var j, jl; - - var nVertexElements = this.attributes[ "position" ].array.length; - - if ( this.attributes[ "normal" ] === undefined ) { - - this.attributes[ "normal" ] = { - - itemSize: 3, - array: new Float32Array( nVertexElements ) - - }; - - } else { - - // reset existing normals to zero - - for ( i = 0, il = this.attributes[ "normal" ].array.length; i < il; i ++ ) { - - this.attributes[ "normal" ].array[ i ] = 0; - - } - - } - - var positions = this.attributes[ "position" ].array; - var normals = this.attributes[ "normal" ].array; - - var vA, vB, vC, x, y, z, - - pA = new THREE.Vector3(), - pB = new THREE.Vector3(), - pC = new THREE.Vector3(), - - cb = new THREE.Vector3(), - ab = new THREE.Vector3(); - - // indexed elements - - if ( this.attributes[ "index" ] ) { - - var indices = this.attributes[ "index" ].array; - - var offsets = this.offsets; - - for ( j = 0, jl = offsets.length; j < jl; ++ j ) { - - var start = offsets[ j ].start; - var count = offsets[ j ].count; - var index = offsets[ j ].index; - - for ( i = start, il = start + count; i < il; i += 3 ) { - - vA = index + indices[ i ]; - vB = index + indices[ i + 1 ]; - vC = index + indices[ i + 2 ]; - - x = positions[ vA * 3 ]; - y = positions[ vA * 3 + 1 ]; - z = positions[ vA * 3 + 2 ]; - pA.set( x, y, z ); - - x = positions[ vB * 3 ]; - y = positions[ vB * 3 + 1 ]; - z = positions[ vB * 3 + 2 ]; - pB.set( x, y, z ); - - x = positions[ vC * 3 ]; - y = positions[ vC * 3 + 1 ]; - z = positions[ vC * 3 + 2 ]; - pC.set( x, y, z ); - - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); - - normals[ vA * 3 ] += cb.x; - normals[ vA * 3 + 1 ] += cb.y; - normals[ vA * 3 + 2 ] += cb.z; - - normals[ vB * 3 ] += cb.x; - normals[ vB * 3 + 1 ] += cb.y; - normals[ vB * 3 + 2 ] += cb.z; - - normals[ vC * 3 ] += cb.x; - normals[ vC * 3 + 1 ] += cb.y; - normals[ vC * 3 + 2 ] += cb.z; - - } - - } - - // non-indexed elements (unconnected triangle soup) - - } else { - - for ( i = 0, il = positions.length; i < il; i += 9 ) { - - x = positions[ i ]; - y = positions[ i + 1 ]; - z = positions[ i + 2 ]; - pA.set( x, y, z ); - - x = positions[ i + 3 ]; - y = positions[ i + 4 ]; - z = positions[ i + 5 ]; - pB.set( x, y, z ); - - x = positions[ i + 6 ]; - y = positions[ i + 7 ]; - z = positions[ i + 8 ]; - pC.set( x, y, z ); - - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); - - normals[ i ] = cb.x; - normals[ i + 1 ] = cb.y; - normals[ i + 2 ] = cb.z; - - normals[ i + 3 ] = cb.x; - normals[ i + 4 ] = cb.y; - normals[ i + 5 ] = cb.z; - - normals[ i + 6 ] = cb.x; - normals[ i + 7 ] = cb.y; - normals[ i + 8 ] = cb.z; - - } - - } - - this.normalizeNormals(); - - this.normalsNeedUpdate = true; - - } - - }, - - normalizeNormals: function () { - - var normals = this.attributes[ "normal" ].array; - - var x, y, z, n; - - for ( var i = 0, il = normals.length; i < il; i += 3 ) { - - x = normals[ i ]; - y = normals[ i + 1 ]; - z = normals[ i + 2 ]; - - n = 1.0 / Math.sqrt( x * x + y * y + z * z ); - - normals[ i ] *= n; - normals[ i + 1 ] *= n; - normals[ i + 2 ] *= n; - - } - - }, - - computeTangents: function () { - - // based on http://www.terathon.com/code/tangent.html - // (per vertex tangents) - - if ( this.attributes[ "index" ] === undefined || - this.attributes[ "position" ] === undefined || - this.attributes[ "normal" ] === undefined || - this.attributes[ "uv" ] === undefined ) { - - THREE.onwarning( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" ); - return; - - } - - var indices = this.attributes[ "index" ].array; - var positions = this.attributes[ "position" ].array; - var normals = this.attributes[ "normal" ].array; - var uvs = this.attributes[ "uv" ].array; - - var nVertices = positions.length / 3; - - if ( this.attributes[ "tangent" ] === undefined ) { - - var nTangentElements = 4 * nVertices; - - this.attributes[ "tangent" ] = { - - itemSize: 4, - array: new Float32Array( nTangentElements ) - - }; - - } - - var tangents = this.attributes[ "tangent" ].array; - - var tan1 = [], tan2 = []; - - for ( var k = 0; k < nVertices; k ++ ) { - - tan1[ k ] = new THREE.Vector3(); - tan2[ k ] = new THREE.Vector3(); - - } - - var xA, yA, zA, - xB, yB, zB, - xC, yC, zC, - - uA, vA, - uB, vB, - uC, vC, - - x1, x2, y1, y2, z1, z2, - s1, s2, t1, t2, r; - - var sdir = new THREE.Vector3(), tdir = new THREE.Vector3(); - - function handleTriangle( a, b, c ) { - - xA = positions[ a * 3 ]; - yA = positions[ a * 3 + 1 ]; - zA = positions[ a * 3 + 2 ]; - - xB = positions[ b * 3 ]; - yB = positions[ b * 3 + 1 ]; - zB = positions[ b * 3 + 2 ]; - - xC = positions[ c * 3 ]; - yC = positions[ c * 3 + 1 ]; - zC = positions[ c * 3 + 2 ]; - - uA = uvs[ a * 2 ]; - vA = uvs[ a * 2 + 1 ]; - - uB = uvs[ b * 2 ]; - vB = uvs[ b * 2 + 1 ]; - - uC = uvs[ c * 2 ]; - vC = uvs[ c * 2 + 1 ]; - - x1 = xB - xA; - x2 = xC - xA; - - y1 = yB - yA; - y2 = yC - yA; - - z1 = zB - zA; - z2 = zC - zA; - - s1 = uB - uA; - s2 = uC - uA; - - t1 = vB - vA; - t2 = vC - vA; - - r = 1.0 / ( s1 * t2 - s2 * t1 ); - - sdir.set( - ( t2 * x1 - t1 * x2 ) * r, - ( t2 * y1 - t1 * y2 ) * r, - ( t2 * z1 - t1 * z2 ) * r - ); - - tdir.set( - ( s1 * x2 - s2 * x1 ) * r, - ( s1 * y2 - s2 * y1 ) * r, - ( s1 * z2 - s2 * z1 ) * r - ); - - tan1[ a ].add( sdir ); - tan1[ b ].add( sdir ); - tan1[ c ].add( sdir ); - - tan2[ a ].add( tdir ); - tan2[ b ].add( tdir ); - tan2[ c ].add( tdir ); - - } - - var i, il; - var j, jl; - var iA, iB, iC; - - var offsets = this.offsets; - - for ( j = 0, jl = offsets.length; j < jl; ++ j ) { - - var start = offsets[ j ].start; - var count = offsets[ j ].count; - var index = offsets[ j ].index; - - for ( i = start, il = start + count; i < il; i += 3 ) { - - iA = index + indices[ i ]; - iB = index + indices[ i + 1 ]; - iC = index + indices[ i + 2 ]; - - handleTriangle( iA, iB, iC ); - - } - - } - - var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(); - var n = new THREE.Vector3(), n2 = new THREE.Vector3(); - var w, t, test; - - function handleVertex( v ) { - - n.x = normals[ v * 3 ]; - n.y = normals[ v * 3 + 1 ]; - n.z = normals[ v * 3 + 2 ]; - - n2.copy( n ); - - t = tan1[ v ]; - - // Gram-Schmidt orthogonalize - - tmp.copy( t ); - tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); - - // Calculate handedness - - tmp2.crossVectors( n2, t ); - test = tmp2.dot( tan2[ v ] ); - w = ( test < 0.0 ) ? -1.0 : 1.0; - - tangents[ v * 4 ] = tmp.x; - tangents[ v * 4 + 1 ] = tmp.y; - tangents[ v * 4 + 2 ] = tmp.z; - tangents[ v * 4 + 3 ] = w; - - } - - for ( j = 0, jl = offsets.length; j < jl; ++ j ) { - - var start = offsets[ j ].start; - var count = offsets[ j ].count; - var index = offsets[ j ].index; - - for ( i = start, il = start + count; i < il; i += 3 ) { - - iA = index + indices[ i ]; - iB = index + indices[ i + 1 ]; - iC = index + indices[ i + 2 ]; - - handleVertex( iA ); - handleVertex( iB ); - handleVertex( iC ); - - } - - } - - }, - - /* - computeOffsets - Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices. - This method will effectively rewrite the index buffer and remap all attributes to match the new indices. - WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets. - indexBufferSize - Defaults to 65535, but allows for larger or smaller chunks. - */ - computeOffsets: function(indexBufferSize) { - - var size = indexBufferSize; - if(indexBufferSize === undefined) - size = 65535; //WebGL limits type of index buffer values to 16-bit. - - var s = Date.now(); - - var indices = this.attributes['index'].array; - var vertices = this.attributes['position'].array; - - var verticesCount = (vertices.length/3); - var facesCount = (indices.length/3); - - /* - console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length); - console.log("Faces to process: "+(indices.length/3)); - console.log("Reordering "+verticesCount+" vertices."); - */ - - var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers - var indexPtr = 0; - var vertexPtr = 0; - - var offsets = [ { start:0, count:0, index:0 } ]; - var offset = offsets[0]; - - var duplicatedVertices = 0; - var newVerticeMaps = 0; - var faceVertices = new Int32Array(6); - var vertexMap = new Int32Array( vertices.length ); - var revVertexMap = new Int32Array( vertices.length ); - for(var j = 0; j < vertices.length; j++) { vertexMap[j] = -1; revVertexMap[j] = -1; } - - /* - Traverse every face and reorder vertices in the proper offsets of 65k. - We can have more than 65k entries in the index buffer per offset, but only reference 65k values. - */ - for(var findex = 0; findex < facesCount; findex++) { - newVerticeMaps = 0; - - for(var vo = 0; vo < 3; vo++) { - var vid = indices[ findex*3 + vo ]; - if(vertexMap[vid] == -1) { - //Unmapped vertice - faceVertices[vo*2] = vid; - faceVertices[vo*2+1] = -1; - newVerticeMaps++; - } else if(vertexMap[vid] < offset.index) { - //Reused vertices from previous block (duplicate) - faceVertices[vo*2] = vid; - faceVertices[vo*2+1] = -1; - duplicatedVertices++; - } else { - //Reused vertice in the current block - faceVertices[vo*2] = vid; - faceVertices[vo*2+1] = vertexMap[vid]; - } - } - - var faceMax = vertexPtr + newVerticeMaps; - if(faceMax > (offset.index + size)) { - var new_offset = { start:indexPtr, count:0, index:vertexPtr }; - offsets.push(new_offset); - offset = new_offset; - - //Re-evaluate reused vertices in light of new offset. - for(var v = 0; v < 6; v+=2) { - var new_vid = faceVertices[v+1]; - if(new_vid > -1 && new_vid < offset.index) - faceVertices[v+1] = -1; - } - } - - //Reindex the face. - for(var v = 0; v < 6; v+=2) { - var vid = faceVertices[v]; - var new_vid = faceVertices[v+1]; - - if(new_vid === -1) - new_vid = vertexPtr++; - - vertexMap[vid] = new_vid; - revVertexMap[new_vid] = vid; - sortedIndices[indexPtr++] = new_vid - offset.index; //XXX overflows at 16bit - offset.count++; - } - } - - /* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */ - this.reorderBuffers(sortedIndices, revVertexMap, vertexPtr); - this.offsets = offsets; - - /* - var orderTime = Date.now(); - console.log("Reorder time: "+(orderTime-s)+"ms"); - console.log("Duplicated "+duplicatedVertices+" vertices."); - console.log("Compute Buffers time: "+(Date.now()-s)+"ms"); - console.log("Draw offsets: "+offsets.length); - */ - - return offsets; - }, - - /* - reoderBuffers: - Reorder attributes based on a new indexBuffer and indexMap. - indexBuffer - Uint16Array of the new ordered indices. - indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex. - vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack). - */ - reorderBuffers: function(indexBuffer, indexMap, vertexCount) { - - /* Create a copy of all attributes for reordering. */ - var sortedAttributes = {}; - var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; - for( var attr in this.attributes ) { - if(attr == 'index') - continue; - var sourceArray = this.attributes[attr].array; - for ( var i = 0, il = types.length; i < il; i++ ) { - var type = types[i]; - if (sourceArray instanceof type) { - sortedAttributes[attr] = new type( this.attributes[attr].itemSize * vertexCount ); - break; - } - } - } - - /* Move attribute positions based on the new index map */ - for(var new_vid = 0; new_vid < vertexCount; new_vid++) { - var vid = indexMap[new_vid]; - for ( var attr in this.attributes ) { - if(attr == 'index') - continue; - var attrArray = this.attributes[attr].array; - var attrSize = this.attributes[attr].itemSize; - var sortedAttr = sortedAttributes[attr]; - for(var k = 0; k < attrSize; k++) - sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ]; - } - } - - /* Carry the new sorted buffers locally */ - this.attributes['index'].array = indexBuffer; - for ( var attr in this.attributes ) { - if(attr == 'index') - continue; - this.attributes[attr].array = sortedAttributes[attr]; - this.attributes[attr].numItems = this.attributes[attr].itemSize * vertexCount; - } - }, - - clone: function () { - - var geometry = new THREE.BufferGeometry(); - - var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; - - for ( var attr in this.attributes ) { - - var sourceAttr = this.attributes[ attr ]; - var sourceArray = sourceAttr.array; - - var attribute = { - - itemSize: sourceAttr.itemSize, - array: null - - }; - - for ( var i = 0, il = types.length; i < il; i ++ ) { - - var type = types[ i ]; - - if ( sourceArray instanceof type ) { - - attribute.array = new type( sourceArray ); - break; - - } - - } - - geometry.attributes[ attr ] = attribute; - - } - - for ( var i = 0, il = this.offsets.length; i < il; i ++ ) { - - var offset = this.offsets[ i ]; - - geometry.offsets.push( { - - start: offset.start, - index: offset.index, - count: offset.count - - } ); - - } - - return geometry; - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author kile / http://kile.stravaganza.org/ - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author bhouston / http://exocortex.com - */ - -THREE.Geometry = function () { - - this.id = THREE.GeometryIdCount ++; - this.uuid = THREE.Math.generateUUID(); - this.className = "Geometry"; - - this.name = ''; - - this.vertices = []; - this.colors = []; // one-to-one vertex colors, used in ParticleSystem and Line - - this.faces = []; - - this.faceVertexUvs = [[]]; - - this.morphTargets = []; - this.morphColors = []; - this.morphNormals = []; - - this.skinWeights = []; - this.skinIndices = []; - - this.lineDistances = []; - - this.boundingBox = null; - this.boundingSphere = null; - - this.hasTangents = true; - - this.dynamic = true; // the intermediate typed arrays will be deleted when set to false - - // update flags - - this.verticesNeedUpdate = false; - this.elementsNeedUpdate = false; - this.uvsNeedUpdate = false; - this.normalsNeedUpdate = false; - this.tangentsNeedUpdate = false; - this.colorsNeedUpdate = false; - this.lineDistancesNeedUpdate = false; - - this.buffersNeedUpdate = false; - -}; - -THREE.Geometry.prototype = { - - constructor: THREE.Geometry, - - applyMatrix: function ( matrix ) { - - var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - - for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { - - var vertex = this.vertices[ i ]; - vertex.applyMatrix4( matrix ); - - } - - for ( var i = 0, il = this.faces.length; i < il; i ++ ) { - - var face = this.faces[ i ]; - face.normal.applyMatrix3( normalMatrix ).normalize(); - - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - - face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); - - } - - face.centroid.applyMatrix4( matrix ); - - } - - if ( this.boundingBox instanceof THREE.Box3 ) { - - this.computeBoundingBox(); - - } - - if ( this.boundingSphere instanceof THREE.Sphere ) { - - this.computeBoundingSphere(); - - } - - }, - - computeCentroids: function () { - - var f, fl, face; - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - face.centroid.set( 0, 0, 0 ); - - face.centroid.add( this.vertices[ face.a ] ); - face.centroid.add( this.vertices[ face.b ] ); - face.centroid.add( this.vertices[ face.c ] ); - face.centroid.divideScalar( 3 ); - - } - - }, - - computeFaceNormals: function () { - - var cb = new THREE.Vector3(), ab = new THREE.Vector3(); - - for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { - - var face = this.faces[ f ]; - - var vA = this.vertices[ face.a ]; - var vB = this.vertices[ face.b ]; - var vC = this.vertices[ face.c ]; - - cb.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - cb.cross( ab ); - - cb.normalize(); - - face.normal.copy( cb ); - - } - - }, - - computeVertexNormals: function ( areaWeighted ) { - - var v, vl, f, fl, face, vertices; - - vertices = new Array( this.vertices.length ); - - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - - vertices[ v ] = new THREE.Vector3(); - - } - - if ( areaWeighted ) { - - // vertex normals weighted by triangle areas - // http://www.iquilezles.org/www/articles/normals/normals.htm - - var vA, vB, vC, vD; - var cb = new THREE.Vector3(), ab = new THREE.Vector3(), - db = new THREE.Vector3(), dc = new THREE.Vector3(), bc = new THREE.Vector3(); - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - vA = this.vertices[ face.a ]; - vB = this.vertices[ face.b ]; - vC = this.vertices[ face.c ]; - - cb.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - cb.cross( ab ); - - vertices[ face.a ].add( cb ); - vertices[ face.b ].add( cb ); - vertices[ face.c ].add( cb ); - - } - - } else { - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - vertices[ face.a ].add( face.normal ); - vertices[ face.b ].add( face.normal ); - vertices[ face.c ].add( face.normal ); - - } - - } - - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - - vertices[ v ].normalize(); - - } - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - face.vertexNormals[ 0 ] = vertices[ face.a ].clone(); - face.vertexNormals[ 1 ] = vertices[ face.b ].clone(); - face.vertexNormals[ 2 ] = vertices[ face.c ].clone(); - - } - - }, - - computeMorphNormals: function () { - - var i, il, f, fl, face; - - // save original normals - // - create temp variables on first access - // otherwise just copy (for faster repeated calls) - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - if ( ! face.__originalFaceNormal ) { - - face.__originalFaceNormal = face.normal.clone(); - - } else { - - face.__originalFaceNormal.copy( face.normal ); - - } - - if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; - - for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { - - if ( ! face.__originalVertexNormals[ i ] ) { - - face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); - - } else { - - face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); - - } - - } - - } - - // use temp geometry to compute face and vertex normals for each morph - - var tmpGeo = new THREE.Geometry(); - tmpGeo.faces = this.faces; - - for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { - - // create on first access - - if ( ! this.morphNormals[ i ] ) { - - this.morphNormals[ i ] = {}; - this.morphNormals[ i ].faceNormals = []; - this.morphNormals[ i ].vertexNormals = []; - - var dstNormalsFace = this.morphNormals[ i ].faceNormals; - var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; - - var faceNormal, vertexNormals; - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - faceNormal = new THREE.Vector3(); - vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() }; - - dstNormalsFace.push( faceNormal ); - dstNormalsVertex.push( vertexNormals ); - - } - - } - - var morphNormals = this.morphNormals[ i ]; - - // set vertices to morph target - - tmpGeo.vertices = this.morphTargets[ i ].vertices; - - // compute morph normals - - tmpGeo.computeFaceNormals(); - tmpGeo.computeVertexNormals(); - - // store morph normals - - var faceNormal, vertexNormals; - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - faceNormal = morphNormals.faceNormals[ f ]; - vertexNormals = morphNormals.vertexNormals[ f ]; - - faceNormal.copy( face.normal ); - - vertexNormals.a.copy( face.vertexNormals[ 0 ] ); - vertexNormals.b.copy( face.vertexNormals[ 1 ] ); - vertexNormals.c.copy( face.vertexNormals[ 2 ] ); - - } - - } - - // restore original normals - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - face.normal = face.__originalFaceNormal; - face.vertexNormals = face.__originalVertexNormals; - - } - - }, - - computeTangents: function () { - - // based on http://www.terathon.com/code/tangent.html - // tangents go to vertices - - var f, fl, v, vl, i, il, vertexIndex, - face, uv, vA, vB, vC, uvA, uvB, uvC, - x1, x2, y1, y2, z1, z2, - s1, s2, t1, t2, r, t, test, - tan1 = [], tan2 = [], - sdir = new THREE.Vector3(), tdir = new THREE.Vector3(), - tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(), - n = new THREE.Vector3(), w; - - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { - - tan1[ v ] = new THREE.Vector3(); - tan2[ v ] = new THREE.Vector3(); - - } - - function handleTriangle( context, a, b, c, ua, ub, uc ) { - - vA = context.vertices[ a ]; - vB = context.vertices[ b ]; - vC = context.vertices[ c ]; - - uvA = uv[ ua ]; - uvB = uv[ ub ]; - uvC = uv[ uc ]; - - x1 = vB.x - vA.x; - x2 = vC.x - vA.x; - y1 = vB.y - vA.y; - y2 = vC.y - vA.y; - z1 = vB.z - vA.z; - z2 = vC.z - vA.z; - - s1 = uvB.x - uvA.x; - s2 = uvC.x - uvA.x; - t1 = uvB.y - uvA.y; - t2 = uvC.y - uvA.y; - - r = 1.0 / ( s1 * t2 - s2 * t1 ); - sdir.set( ( t2 * x1 - t1 * x2 ) * r, - ( t2 * y1 - t1 * y2 ) * r, - ( t2 * z1 - t1 * z2 ) * r ); - tdir.set( ( s1 * x2 - s2 * x1 ) * r, - ( s1 * y2 - s2 * y1 ) * r, - ( s1 * z2 - s2 * z1 ) * r ); - - tan1[ a ].add( sdir ); - tan1[ b ].add( sdir ); - tan1[ c ].add( sdir ); - - tan2[ a ].add( tdir ); - tan2[ b ].add( tdir ); - tan2[ c ].add( tdir ); - - } - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents - - handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 ); - - } - - var faceIndex = [ 'a', 'b', 'c', 'd' ]; - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - - for ( i = 0; i < Math.min( face.vertexNormals.length, 3 ); i++ ) { - - n.copy( face.vertexNormals[ i ] ); - - vertexIndex = face[ faceIndex[ i ] ]; - - t = tan1[ vertexIndex ]; - - // Gram-Schmidt orthogonalize - - tmp.copy( t ); - tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); - - // Calculate handedness - - tmp2.crossVectors( face.vertexNormals[ i ], t ); - test = tmp2.dot( tan2[ vertexIndex ] ); - w = (test < 0.0) ? -1.0 : 1.0; - - face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w ); - - } - - } - - this.hasTangents = true; - - }, - - computeLineDistances: function ( ) { - - var d = 0; - var vertices = this.vertices; - - for ( var i = 0, il = vertices.length; i < il; i ++ ) { - - if ( i > 0 ) { - - d += vertices[ i ].distanceTo( vertices[ i - 1 ] ); - - } - - this.lineDistances[ i ] = d; - - } - - }, - - computeBoundingBox: function () { - - if ( this.boundingBox === null ) { - - this.boundingBox = new THREE.Box3(); - - } - - this.boundingBox.setFromPoints( this.vertices ); - - }, - - computeBoundingSphere: function () { - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new THREE.Sphere(); - - } - - this.boundingSphere.setFromPoints( this.vertices ); - - }, - - /* - * Checks for duplicate vertices with hashmap. - * Duplicated vertices are removed - * and faces' vertices are updated. - */ - - mergeVertices: function () { - - var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique) - var unique = [], changes = []; - - var v, key; - var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001 - var precision = Math.pow( 10, precisionPoints ); - var i,il, face; - var indices, k, j, jl, u; - - for ( i = 0, il = this.vertices.length; i < il; i ++ ) { - - v = this.vertices[ i ]; - key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); - - if ( verticesMap[ key ] === undefined ) { - - verticesMap[ key ] = i; - unique.push( this.vertices[ i ] ); - changes[ i ] = unique.length - 1; - - } else { - - //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); - changes[ i ] = changes[ verticesMap[ key ] ]; - - } - - }; - - - // if faces are completely degenerate after merging vertices, we - // have to remove them from the geometry. - var faceIndicesToRemove = []; - - for( i = 0, il = this.faces.length; i < il; i ++ ) { - - face = this.faces[ i ]; - - face.a = changes[ face.a ]; - face.b = changes[ face.b ]; - face.c = changes[ face.c ]; - - indices = [ face.a, face.b, face.c ]; - - var dupIndex = -1; - - // if any duplicate vertices are found in a Face3 - // we have to remove the face as nothing can be saved - for ( var n = 0; n < 3; n ++ ) { - if ( indices[ n ] == indices[ ( n + 1 ) % 3 ] ) { - - dupIndex = n; - faceIndicesToRemove.push( i ); - break; - - } - } - - } - - for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { - var idx = faceIndicesToRemove[ i ]; - - this.faces.splice( idx, 1 ); - - for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { - - this.faceVertexUvs[ j ].splice( idx, 1 ); - - } - - } - - // Use unique set of vertices - - var diff = this.vertices.length - unique.length; - this.vertices = unique; - return diff; - - }, - - // Geometry splitting - - makeGroups: ( function () { - - var geometryGroupCounter = 0; - - return function ( usesFaceMaterial ) { - - var f, fl, face, materialIndex, - groupHash, hash_map = {}; - - var numMorphTargets = this.morphTargets.length; - var numMorphNormals = this.morphNormals.length; - - this.geometryGroups = {}; - - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - - face = this.faces[ f ]; - materialIndex = usesFaceMaterial ? face.materialIndex : 0; - - if ( ! ( materialIndex in hash_map ) ) { - - hash_map[ materialIndex ] = { 'hash': materialIndex, 'counter': 0 }; - - } - - groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; - - if ( ! ( groupHash in this.geometryGroups ) ) { - - this.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; - - } - - if ( this.geometryGroups[ groupHash ].vertices + 3 > 65535 ) { - - hash_map[ materialIndex ].counter += 1; - groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; - - if ( ! ( groupHash in this.geometryGroups ) ) { - - this.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; - - } - - } - - this.geometryGroups[ groupHash ].faces3.push( f ); - this.geometryGroups[ groupHash ].vertices += 3; - - } - - this.geometryGroupsList = []; - - for ( var g in this.geometryGroups ) { - - this.geometryGroups[ g ].id = geometryGroupCounter ++; - - this.geometryGroupsList.push( this.geometryGroups[ g ] ); - - } - - }; - - } )(), - - clone: function () { - - var geometry = new THREE.Geometry(); - - var vertices = this.vertices; - - for ( var i = 0, il = vertices.length; i < il; i ++ ) { - - geometry.vertices.push( vertices[ i ].clone() ); - - } - - var faces = this.faces; - - for ( var i = 0, il = faces.length; i < il; i ++ ) { - - geometry.faces.push( faces[ i ].clone() ); - - } - - var uvs = this.faceVertexUvs[ 0 ]; - - for ( var i = 0, il = uvs.length; i < il; i ++ ) { - - var uv = uvs[ i ], uvCopy = []; - - for ( var j = 0, jl = uv.length; j < jl; j ++ ) { - - uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); - - } - - geometry.faceVertexUvs[ 0 ].push( uvCopy ); - - } - - geometry.morphTargets = this.morphTargets.slice( 0 ); - geometry.morphColors = this.morphColors.slice( 0 ); - geometry.morphNormals = this.morphNormals.slice( 0 ); - geometry.skinWeights = this.skinWeights.slice( 0 ); - geometry.skinIndices = this.skinIndices.slice( 0 ); - geometry.lineDistances = this.lineDistances.slice( 0 ); - - if( this.boundingBox ) geometry.boundingBox = this.boundingBox.clone(); - if( this.boundingSphere ) geometry.boundingSphere = this.boundingSphere.clone(); - - geometry.hasTangents = this.hasTangents; - - geometry.dynamic = this.dynamic; // the intermediate typed arrays will be deleted when set to false - - return geometry; - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype ); - -THREE.GeometryIdCount = 0; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Geometry2 = function ( size ) { - - THREE.BufferGeometry.call( this ); - this.className = "Geometry2"; - - this.vertices = this.addAttribute( 'position', Float32Array, size, 3 ).array; - this.normals = this.addAttribute( 'normal', Float32Array, size, 3 ).array; - this.uvs = this.addAttribute( 'uv', Float32Array, size, 2 ).array; - - this.boundingBox = null; - this.boundingSphere = null; - -}; - -THREE.Geometry2.prototype = Object.create( THREE.BufferGeometry.prototype ); -/** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author WestLangley / http://github.com/WestLangley -*/ - -THREE.Camera = function () { - - THREE.Object3D.call( this ); - - this.matrixWorldInverse = new THREE.Matrix4(); - this.projectionMatrix = new THREE.Matrix4(); - - this.normalizedViewport = { x: 0, y: 0, width: 1.0, height: 1.0 }; -}; - -THREE.Camera.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.Camera.prototype.lookAt = function () { - - // This routine does not support cameras with rotated and/or translated parent(s) - - var m1 = new THREE.Matrix4(); - - return function ( vector ) { - - m1.lookAt( this.position, vector, this.up ); - - this.quaternion.setFromRotationMatrix( m1 ); - - }; - -}(); - -THREE.Camera.prototype.clone = function (camera) { - - if ( camera === undefined ) camera = new THREE.Camera(); - - THREE.Object3D.prototype.clone.call( this, camera ); - - camera.matrixWorldInverse.copy( this.matrixWorldInverse ); - camera.projectionMatrix.copy( this.projectionMatrix ); - - camera.normalizedViewport = { - x: this.normalizedViewport.x, - y: this.normalizedViewport.y, - width: this.normalizedViewport.width, - height: this.normalizedViewport.height - }; - - return camera; -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) { - - THREE.Camera.call( this ); - - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; - - this.near = ( near !== undefined ) ? near : 0.1; - this.far = ( far !== undefined ) ? far : 2000; - - this.updateProjectionMatrix(); - -}; - -THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype ); - -THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () { - - this.projectionMatrix.makeOrthographic( this.left, this.right, this.top, this.bottom, this.near, this.far ); - - - - var viewportMatrix = new THREE.Matrix4(); - viewportMatrix.elements[0] *= this.normalizedViewport.width; - viewportMatrix.elements[1] *= this.normalizedViewport.height; - viewportMatrix.elements[12] += this.normalizedViewport.x; - viewportMatrix.elements[13] += this.normalizedViewport.y; - this.projectionMatrix = viewportMatrix.multiply( this.projectionMatrix ); -}; - -THREE.OrthographicCamera.prototype.clone = function () { - - var camera = new THREE.OrthographicCamera(); - - THREE.Camera.prototype.clone.call( this, camera ); - - camera.left = this.left; - camera.right = this.right; - camera.top = this.top; - camera.bottom = this.bottom; - - camera.near = this.near; - camera.far = this.far; - - return camera; -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author greggman / http://games.greggman.com/ - * @author zz85 / http://www.lab4games.net/zz85/blog - */ - -THREE.PerspectiveCamera = function ( fov, aspect, near, far, filmSize, filmOffset ) { - - THREE.Camera.call( this ); - - this.fov = fov !== undefined ? fov : 50; - this.aspect = aspect !== undefined ? aspect : 1; - this.near = near !== undefined ? near : 0.1; - this.far = far !== undefined ? far : 2000; - this.filmSize = filmSize !== undefined ? filmSize : new THREE.Vector2( 1, 1 ); - this.filmOffset = filmOffset !== undefined ? filmOffset : new THREE.Vector2( 0, 0 ); - - this.updateProjectionMatrix(); - -}; - -THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype ); - - -/** - * Uses Focal Length (in mm) to estimate and set FOV - * 35mm (fullframe) camera is used if frame size is not specified; - * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html - */ - -THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) { - - if ( frameHeight === undefined ) frameHeight = 24; - - this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); - this.updateProjectionMatrix(); - -} - - -/** - * Sets an offset in a larger frustum. This is useful for multi-window or - * multi-monitor/multi-machine setups. - * - * For example, if you have 3x2 monitors and each monitor is 1920x1080 and - * the monitors are in grid like this - * - * +---+---+---+ - * | A | B | C | - * +---+---+---+ - * | D | E | F | - * +---+---+---+ - * - * then for each monitor you would call it like this - * - * var w = 1920; - * var h = 1080; - * var fullWidth = w * 3; - * var fullHeight = h * 2; - * - * --A-- - * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); - * --B-- - * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); - * --C-- - * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); - * --D-- - * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); - * --E-- - * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); - * --F-- - * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); - * - * Note there is no reason monitors have to be the same size or in a grid. - */ - -THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) { - - this.fullWidth = fullWidth; - this.fullHeight = fullHeight; - this.x = x; - this.y = y; - this.width = width; - this.height = height; - - this.updateProjectionMatrix(); - -}; - - -THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { - - if ( this.fullWidth ) { - - var aspect = this.fullWidth / this.fullHeight; - var top = Math.tan( THREE.Math.degToRad( this.fov * 0.5 ) ) * this.near; - var bottom = - top; - var left = aspect * bottom; - var right = aspect * top; - var width = Math.abs( right - left ); - var height = Math.abs( top - bottom ); - - this.projectionMatrix.makeFrustum( - left + this.x * width / this.fullWidth, - left + ( this.x + this.width ) * width / this.fullWidth, - top - ( this.y + this.height ) * height / this.fullHeight, - top - this.y * height / this.fullHeight, - this.near, - this.far, - this.filmOffset, - this.filmSize - ); - - } else { - - this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far, this.filmOffset, this.filmSize ); - - } - - var viewportMatrix = new THREE.Matrix4(); - viewportMatrix.elements[0] *= this.normalizedViewport.width; - viewportMatrix.elements[1] *= this.normalizedViewport.height; - viewportMatrix.elements[12] += this.normalizedViewport.x; - viewportMatrix.elements[13] += this.normalizedViewport.y; - this.projectionMatrix = viewportMatrix.multiply( this.projectionMatrix ); - -}; - -THREE.PerspectiveCamera.prototype.clone = function () { - - var camera = new THREE.PerspectiveCamera(); - - THREE.Camera.prototype.clone.call( this, camera ); - - camera.fov = this.fov; - camera.aspect = this.aspect; - camera.near = this.near; - camera.far = this.far; - camera.filmSize = this.filmSize; - camera.filmOffset = this.filmOffset; - - return camera; -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Light = function ( color ) { - - THREE.Object3D.call( this ); - - this.color = new THREE.Color( color ); - -}; - -THREE.Light.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.Light.prototype.clone = function ( light ) { - - if ( light === undefined ) light = new THREE.Light(); - - THREE.Object3D.prototype.clone.call( this, light ); - - light.color.copy( this.color ); - - return light; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.AmbientLight = function ( color ) { - - THREE.Light.call( this, color ); - -}; - -THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype ); - -THREE.AmbientLight.prototype.clone = function () { - - var light = new THREE.AmbientLight(); - - THREE.Light.prototype.clone.call( this, light ); - - return light; - -}; - -/** - * @author bhouston / http://clara.io/ - * @author MPanknin / http://www.redplant.de/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.AreaLight = function ( color, intensity, distance, decayExponent, physicalFalloff ) { - - THREE.Light.call( this, color ); - - this.position.set( 0, 1, 0 ); - this.target = new THREE.Object3D(); - - this.intensity = ( intensity !== undefined ) ? intensity : 1; - this.distance = ( distance !== undefined ) ? distance : 0; - this.decayExponent = ( decayExponent !== undefined ) ? decayExponent : 0; // for physically correct lights, should be 2. - this.physicalFalloff = ( physicalFalloff !== undefined ) ? physicalFalloff : false; - - this.width = 1.0; - this.height = 1.0; - - // TODO: implement shadow maps. -bhouston, Oct 15, 2014 -}; - -THREE.AreaLight.prototype = Object.create( THREE.Light.prototype ); - -THREE.AreaLight.prototype.clone = function () { - - var light = new THREE.AreaLight(); - - THREE.Light.prototype.clone.call( this, light ); - - light.target = this.target.clone(); - - light.intensity = this.intensity; - light.distance = this.distance; - light.decayExponent = this.decayExponent; - light.physicalFalloff = this.physicalFalloff; - - light.width = this.width; - light.height = this.height; - - return light; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.DirectionalLight = function ( color, intensity ) { - - THREE.Light.call( this, color ); - - this.position.set( 0, 1, 0 ); - this.target = new THREE.Object3D(); - - this.intensity = ( intensity !== undefined ) ? intensity : 1; - - this.castShadow = false; - this.onlyShadow = false; - - // - - this.shadowCameraNear = 50; - this.shadowCameraFar = 5000; - - this.shadowCameraLeft = -500; - this.shadowCameraRight = 500; - this.shadowCameraTop = 500; - this.shadowCameraBottom = -500; - - this.shadowCameraVisible = false; - - this.shadowBias = 0; - this.shadowDarkness = 0.5; - - this.shadowMapWidth = 512; - this.shadowMapHeight = 512; - - // - - this.shadowCascade = false; - - this.shadowCascadeOffset = new THREE.Vector3( 0, 0, -1000 ); - this.shadowCascadeCount = 2; - - this.shadowCascadeBias = [ 0, 0, 0 ]; - this.shadowCascadeWidth = [ 512, 512, 512 ]; - this.shadowCascadeHeight = [ 512, 512, 512 ]; - - this.shadowCascadeNearZ = [ -1.000, 0.990, 0.998 ]; - this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; - - this.shadowCascadeArray = []; - - // - - this.shadowMap = null; - this.shadowMapSize = null; - this.shadowCamera = null; - this.shadowMatrix = null; - -}; - -THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype ); - -THREE.DirectionalLight.prototype.clone = function () { - - var light = new THREE.DirectionalLight(); - - THREE.Light.prototype.clone.call( this, light ); - - light.target = this.target.clone(); - - light.intensity = this.intensity; - - light.castShadow = this.castShadow; - light.onlyShadow = this.onlyShadow; - - return light; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.HemisphereLight = function ( skyColor, groundColor, intensity ) { - - THREE.Light.call( this, skyColor ); - - this.position.set( 0, 100, 0 ); - - this.groundColor = new THREE.Color( groundColor ); - this.intensity = ( intensity !== undefined ) ? intensity : 1; - -}; - -THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype ); - -THREE.HemisphereLight.prototype.clone = function () { - - var light = new THREE.HemisphereLight(); - - THREE.Light.prototype.clone.call( this, light ); - - light.groundColor.copy( this.groundColor ); - light.intensity = this.intensity; - - return light; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.PointLight = function ( color, intensity, distance, decayExponent, physicalFalloff ) { - - THREE.Light.call( this, color ); - - this.intensity = ( intensity !== undefined ) ? intensity : 1; - this.distance = ( distance !== undefined ) ? distance : 0; - this.decayExponent = ( decayExponent !== undefined ) ? decayExponent : 0;; // for physically correct lights, should be 2. - this.physicalFalloff = ( physicalFalloff !== undefined ) ? physicalFalloff : false; -}; - -THREE.PointLight.prototype = Object.create( THREE.Light.prototype ); - -THREE.PointLight.prototype.clone = function () { - - var light = new THREE.PointLight(); - - THREE.Light.prototype.clone.call( this, light ); - - light.intensity = this.intensity; - light.distance = this.distance; - light.decayExponent = this.decayExponent; - light.physicalFalloff = this.physicalFalloff; - - return light; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.SpotLight = function ( color, intensity, distance, angle, exponent, decayExponent, physicalFalloff ) { - - THREE.Light.call( this, color ); - - this.position.set( 0, 1, 0 ); - this.target = new THREE.Object3D(); - - this.intensity = ( intensity !== undefined ) ? intensity : 1; - this.distance = ( distance !== undefined ) ? distance : 0; - this.decayExponent = ( decayExponent !== undefined ) ? decayExponent : 0;; // for physically correct lights, should be 2. - this.physicalFalloff = ( physicalFalloff !== undefined ) ? physicalFalloff : false; - - this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; - this.exponent = ( exponent !== undefined ) ? exponent : 10; - - this.castShadow = false; - this.onlyShadow = false; - - // - - this.shadowCameraNear = 50; - this.shadowCameraFar = 5000; - this.shadowCameraFov = 50; - - this.shadowCameraVisible = false; - - this.shadowBias = 0; - this.shadowDarkness = 0.5; - - this.shadowMapWidth = 512; - this.shadowMapHeight = 512; - - // - - this.shadowMap = null; - this.shadowMapSize = null; - this.shadowCamera = null; - this.shadowMatrix = null; - -}; - -THREE.SpotLight.prototype = Object.create( THREE.Light.prototype ); - -THREE.SpotLight.prototype.clone = function () { - - var light = new THREE.SpotLight(); - - THREE.Light.prototype.clone.call( this, light ); - - light.target = this.target.clone(); - - light.intensity = this.intensity; - light.distance = this.distance; - light.angle = this.angle; - light.exponent = this.exponent; - light.decayExponent = this.decayExponent; - light.physicalFalloff = this.physicalFalloff; - - light.castShadow = this.castShadow; - light.onlyShadow = this.onlyShadow; - - return light; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Loader = function ( showStatus ) { - - this.showStatus = showStatus; - this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null; - - this.onLoadStart = function () {}; - this.onLoadProgress = function () {}; - this.onLoadComplete = function () {}; - -}; - -THREE.Loader.prototype = { - - constructor: THREE.Loader, - - crossOrigin: undefined, - - addStatusElement: function () { - - var e = document.createElement( "div" ); - - e.style.position = "absolute"; - e.style.right = "0px"; - e.style.top = "0px"; - e.style.fontSize = "0.8em"; - e.style.textAlign = "left"; - e.style.background = "rgba(0,0,0,0.25)"; - e.style.color = "#fff"; - e.style.width = "120px"; - e.style.padding = "0.5em 0.5em 0.5em 0.5em"; - e.style.zIndex = 1000; - - e.innerHTML = "Loading ..."; - - return e; - - }, - - updateProgress: function ( progress ) { - - var message = "Loaded "; - - if ( progress.total ) { - - message += ( 100 * progress.loaded / progress.total ).toFixed(0) + "%"; - - - } else { - - message += ( progress.loaded / 1000 ).toFixed(2) + " KB"; - - } - - this.statusDomElement.innerHTML = message; - - }, - - extractUrlBase: function ( url ) { - - var parts = url.split( '/' ); - - if ( parts.length === 1 ) return './'; - - parts.pop(); - - return parts.join( '/' ) + '/'; - - }, - - initMaterials: function ( materials, texturePath ) { - - var array = []; - - for ( var i = 0; i < materials.length; ++ i ) { - - array[ i ] = THREE.Loader.prototype.createMaterial( materials[ i ], texturePath ); - - } - - return array; - - }, - - needsTangents: function ( materials ) { - - for( var i = 0, il = materials.length; i < il; i ++ ) { - - var m = materials[ i ]; - - if ( m instanceof THREE.ShaderMaterial ) return true; - - } - - return false; - - }, - - createMaterial: function ( m, texturePath ) { - - var _this = this; - - function is_pow2( n ) { - - var l = Math.log( n ) / Math.LN2; - return Math.floor( l ) == l; - - } - - function nearest_pow2( n ) { - - var l = Math.log( n ) / Math.LN2; - return Math.pow( 2, Math.round( l ) ); - - } - - function load_image( where, url ) { - - var image = new Image(); - - image.onload = function () { - - if ( !is_pow2( this.width ) || !is_pow2( this.height ) ) { - - var width = nearest_pow2( this.width ); - var height = nearest_pow2( this.height ); - - where.image.width = width; - where.image.height = height; - where.image.getContext( '2d' ).drawImage( this, 0, 0, width, height ); - - } else { - - where.image = this; - - } - - where.needsUpdate = true; - - }; - - if ( _this.crossOrigin !== undefined ) image.crossOrigin = _this.crossOrigin; - image.src = url; - - } - - function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) { - - var isCompressed = /\.dds$/i.test( sourceFile ); - - var fullPath = texturePath + sourceFile; - - if ( isCompressed ) { - - var texture = THREE.ImageUtils.loadCompressedTexture( fullPath ); - - where[ name ] = texture; - - } else { - - var texture = document.createElement( 'canvas' ); - - where[ name ] = new THREE.Texture( texture ); - - } - - where[ name ].sourceFile = sourceFile; - - if( repeat ) { - - where[ name ].repeat.set( repeat[ 0 ], repeat[ 1 ] ); - - if ( repeat[ 0 ] !== 1 ) where[ name ].wrapS = THREE.RepeatWrapping; - if ( repeat[ 1 ] !== 1 ) where[ name ].wrapT = THREE.RepeatWrapping; - - } - - if ( offset ) { - - where[ name ].offset.set( offset[ 0 ], offset[ 1 ] ); - - } - - if ( wrap ) { - - var wrapMap = { - "repeat": THREE.RepeatWrapping, - "mirror": THREE.MirroredRepeatWrapping - } - - if ( wrapMap[ wrap[ 0 ] ] !== undefined ) where[ name ].wrapS = wrapMap[ wrap[ 0 ] ]; - if ( wrapMap[ wrap[ 1 ] ] !== undefined ) where[ name ].wrapT = wrapMap[ wrap[ 1 ] ]; - - } - - if ( anisotropy ) { - - where[ name ].anisotropy = anisotropy; - - } - - if ( ! isCompressed ) { - - load_image( where[ name ], fullPath ); - - } - - } - - function rgb2hex( rgb ) { - - return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255; - - } - - // defaults - - var mtype = "MeshLambertMaterial"; - var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false }; - - // parameters from model file - - if ( m.shading ) { - - var shading = m.shading.toLowerCase(); - - if ( shading === "phong" ) mtype = "MeshPhongMaterial"; - else if ( shading === "basic" ) mtype = "MeshBasicMaterial"; - else if ( shading === "physical" ) mtype = "MeshPhysicalMaterial"; - - } - - if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) { - - mpars.blending = THREE[ m.blending ]; - - } - - if ( m.transparent !== undefined || m.opacity < 1.0 ) { - - mpars.transparent = m.transparent; - - } - - if ( m.depthTest !== undefined ) { - - mpars.depthTest = m.depthTest; - - } - - if ( m.depthWrite !== undefined ) { - - mpars.depthWrite = m.depthWrite; - - } - - if ( m.visible !== undefined ) { - - mpars.visible = m.visible; - - } - - if ( m.flipSided !== undefined ) { - - mpars.side = THREE.BackSide; - - } - - if ( m.doubleSided !== undefined ) { - - mpars.side = THREE.DoubleSide; - - } - - if ( m.wireframe !== undefined ) { - - mpars.wireframe = m.wireframe; - - } - - if ( m.vertexColors !== undefined ) { - - if ( m.vertexColors === "face" ) { - - mpars.vertexColors = THREE.FaceColors; - - } else if ( m.vertexColors ) { - - mpars.vertexColors = THREE.VertexColors; - - } - - } - - // colors - - if ( m.colorDiffuse ) { - - mpars.color = rgb2hex( m.colorDiffuse ); - - } else if ( m.DbgColor ) { - - mpars.color = m.DbgColor; - - } - - if ( m.colorSpecular ) { - - mpars.specular = rgb2hex( m.colorSpecular ); - - } - - if ( m.colorAmbient ) { - - mpars.ambient = rgb2hex( m.colorAmbient ); - - } - - // modifiers - - if ( m.transparency ) { - - mpars.opacity = m.transparency; - - } - - if ( m.specularCoef ) { - - mpars.shininess = m.specularCoef; - - } - - // textures - - if ( m.mapDiffuse && texturePath ) { - - create_texture( mpars, "map", m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); - - } - - if ( m.mapLight && texturePath ) { - - create_texture( mpars, "lightMap", m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); - - } - - if ( m.mapBump && texturePath ) { - - create_texture( mpars, "bumpMap", m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); - - } - - if ( m.mapNormal && texturePath ) { - - create_texture( mpars, "normalMap", m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); - - } - - if ( m.mapSpecular && texturePath ) { - - create_texture( mpars, "specularMap", m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); - - } - - // - - if ( m.mapBumpScale ) { - - mpars.bumpScale = m.mapBumpScale; - - } - - // special case for normal mapped material - - if ( m.mapNormal ) { - - var shader = THREE.ShaderLib[ "normalmap" ]; - var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); - - uniforms[ "tNormal" ].value = mpars.normalMap; - - if ( m.mapNormalFactor ) { - - uniforms[ "uNormalScale" ].value.set( m.mapNormalFactor, m.mapNormalFactor ); - - } - - if ( mpars.map ) { - - uniforms[ "tDiffuse" ].value = mpars.map; - uniforms[ "enableDiffuse" ].value = true; - - } - - if ( mpars.specularMap ) { - - uniforms[ "tSpecular" ].value = mpars.specularMap; - uniforms[ "enableSpecular" ].value = true; - - } - - if ( mpars.lightMap ) { - - uniforms[ "tAO" ].value = mpars.lightMap; - uniforms[ "enableAO" ].value = true; - - } - - // for the moment don't handle displacement texture - - uniforms[ "diffuse" ].value.setHex( mpars.color ); - uniforms[ "specular" ].value.setHex( mpars.specular ); - uniforms[ "ambient" ].value.setHex( mpars.ambient ); - - uniforms[ "shininess" ].value = mpars.shininess; - - if ( mpars.opacity !== undefined ) { - - uniforms[ "opacity" ].value = mpars.opacity; - - } - - var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; - var material = new THREE.ShaderMaterial( parameters ); - - if ( mpars.transparent ) { - - material.transparent = true; - - } - - } else { - - var material = new THREE[ mtype ]( mpars ); - - } - - if ( m.DbgName !== undefined ) material.name = m.DbgName; - - return material; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.XHRLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.XHRLoader.prototype = { - - constructor: THREE.XHRLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - var request = new XMLHttpRequest(); - - if ( onLoad !== undefined ) { - - request.addEventListener( 'load', function ( event ) { - - onLoad( event.target.responseText ); - scope.manager.itemEnd( url ); - - }, false ); - - } - - if ( onProgress !== undefined ) { - - request.addEventListener( 'progress', function ( event ) { - - onProgress( event ); - - }, false ); - - } - - if ( onError !== undefined ) { - - request.addEventListener( 'error', function ( event ) { - - onError( event ); - - }, false ); - - } - - if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin; - - request.open( 'GET', url, true ); - request.send( null ); - - scope.manager.itemStart( url ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.ImageLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.ImageLoader.prototype = { - - constructor: THREE.ImageLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - var image = document.createElement( 'img' ); - - if ( onLoad !== undefined ) { - - image.addEventListener( 'load', function ( event ) { - - scope.manager.itemEnd( url ); - onLoad( this ); - - }, false ); - - } - - if ( onProgress !== undefined ) { - - image.addEventListener( 'progress', function ( event ) { - - onProgress( event ); - - }, false ); - - } - - if ( onError !== undefined ) { - - image.addEventListener( 'error', function ( event ) { - - onError( event ); - - }, false ); - - } - - if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; - - image.src = url; - - scope.manager.itemStart( url ); - - return image; - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - } - -} - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.JSONLoader = function ( showStatus ) { - - THREE.Loader.call( this, showStatus ); - - this.withCredentials = false; - -}; - -THREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype ); - -THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) { - - var scope = this; - - // todo: unify load API to for easier SceneLoader use - - texturePath = texturePath && ( typeof texturePath === "string" ) ? texturePath : this.extractUrlBase( url ); - - this.onLoadStart(); - this.loadAjaxJSON( this, url, callback, texturePath ); - -}; - -THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) { - - var xhr = new XMLHttpRequest(); - - var length = 0; - - xhr.onreadystatechange = function () { - - if ( xhr.readyState === xhr.DONE ) { - - if ( xhr.status === 200 || xhr.status === 0 ) { - - if ( xhr.responseText ) { - - var json = JSON.parse( xhr.responseText ); - - if ( json.metadata.type === 'scene' ) { - - THREE.onerror( 'THREE.JSONLoader: "' + url + '" seems to be a Scene. Use THREE.SceneLoader instead.' ); - return; - - } - - var result = context.parse( json, texturePath ); - callback( result.geometry, result.materials ); - - } else { - - THREE.onerror( 'THREE.JSONLoader: "' + url + '" seems to be unreachable or the file is empty.' ); - - } - - // in context of more complex asset initialization - // do not block on single failed file - // maybe should go even one more level up - - context.onLoadComplete(); - - } else { - - THREE.onerror( 'THREE.JSONLoader: Couldn\'t load "' + url + '" (' + xhr.status + ')' ); - - } - - } else if ( xhr.readyState === xhr.LOADING ) { - - if ( callbackProgress ) { - - if ( length === 0 ) { - - length = xhr.getResponseHeader( 'Content-Length' ); - - } - - callbackProgress( { total: length, loaded: xhr.responseText.length } ); - - } - - } else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) { - - if ( callbackProgress !== undefined ) { - - length = xhr.getResponseHeader( "Content-Length" ); - - } - - } - - }; - - xhr.open( "GET", url, true ); - xhr.withCredentials = this.withCredentials; - xhr.send( null ); - -}; - -THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { - - var scope = this, - geometry = new THREE.Geometry(), - scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; - - parseModel( scale ); - - parseSkin(); - parseMorphing( scale ); - - geometry.computeCentroids(); - geometry.computeFaceNormals(); - geometry.computeBoundingSphere(); - - function parseModel( scale ) { - - function isBitSet( value, position ) { - - return value & ( 1 << position ); - - } - - var i, j, fi, - - offset, zLength, - - colorIndex, normalIndex, uvIndex, materialIndex, - - type, - isQuad, - hasMaterial, - hasFaceVertexUv, - hasFaceNormal, hasFaceVertexNormal, - hasFaceColor, hasFaceVertexColor, - - vertex, face, faceA, faceB, color, hex, normal, - - uvLayer, uv, u, v, - - faces = json.faces, - vertices = json.vertices, - normals = json.normals, - colors = json.colors, - - nUvLayers = 0; - - if ( json.uvs !== undefined ) { - - // disregard empty arrays - - for ( i = 0; i < json.uvs.length; i++ ) { - - if ( json.uvs[ i ].length ) nUvLayers ++; - - } - - for ( i = 0; i < nUvLayers; i++ ) { - - geometry.faceVertexUvs[ i ] = []; - - } - - } - - offset = 0; - zLength = vertices.length; - - while ( offset < zLength ) { - - vertex = new THREE.Vector3(); - - vertex.x = vertices[ offset ++ ] * scale; - vertex.y = vertices[ offset ++ ] * scale; - vertex.z = vertices[ offset ++ ] * scale; - - geometry.vertices.push( vertex ); - - } - - offset = 0; - zLength = faces.length; - - while ( offset < zLength ) { - - type = faces[ offset ++ ]; - - - isQuad = isBitSet( type, 0 ); - hasMaterial = isBitSet( type, 1 ); - hasFaceVertexUv = isBitSet( type, 3 ); - hasFaceNormal = isBitSet( type, 4 ); - hasFaceVertexNormal = isBitSet( type, 5 ); - hasFaceColor = isBitSet( type, 6 ); - hasFaceVertexColor = isBitSet( type, 7 ); - - // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); - - if ( isQuad ) { - - faceA = new THREE.Face3(); - faceA.a = faces[ offset ]; - faceA.b = faces[ offset + 1 ]; - faceA.c = faces[ offset + 3 ]; - - faceB = new THREE.Face3(); - faceB.a = faces[ offset + 1 ]; - faceB.b = faces[ offset + 2 ]; - faceB.c = faces[ offset + 3 ]; - - offset += 4; - - if ( hasMaterial ) { - - materialIndex = faces[ offset ++ ]; - faceA.materialIndex = materialIndex; - faceB.materialIndex = materialIndex; - - } - - // to get face <=> uv index correspondence - - fi = geometry.faces.length; - - if ( hasFaceVertexUv ) { - - for ( i = 0; i < nUvLayers; i++ ) { - - uvLayer = json.uvs[ i ]; - - geometry.faceVertexUvs[ i ][ fi ] = []; - geometry.faceVertexUvs[ i ][ fi + 1 ] = [] - - for ( j = 0; j < 4; j ++ ) { - - uvIndex = faces[ offset ++ ]; - - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; - - uv = new THREE.Vector2( u, v ); - - if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); - if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); - - } - - } - - } - - if ( hasFaceNormal ) { - - normalIndex = faces[ offset ++ ] * 3; - - faceA.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); - - faceB.normal.copy( faceA.normal ); - - } - - if ( hasFaceVertexNormal ) { - - for ( i = 0; i < 4; i++ ) { - - normalIndex = faces[ offset ++ ] * 3; - - normal = new THREE.Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); - - - if ( i !== 2 ) faceA.vertexNormals.push( normal ); - if ( i !== 0 ) faceB.vertexNormals.push( normal ); - - } - - } - - - if ( hasFaceColor ) { - - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; - - faceA.color.setHex( hex ); - faceB.color.setHex( hex ); - - } - - - if ( hasFaceVertexColor ) { - - for ( i = 0; i < 4; i++ ) { - - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; - - if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) ); - if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) ); - - } - - } - - geometry.faces.push( faceA ); - geometry.faces.push( faceB ); - - } else { - - face = new THREE.Face3(); - face.a = faces[ offset ++ ]; - face.b = faces[ offset ++ ]; - face.c = faces[ offset ++ ]; - - if ( hasMaterial ) { - - materialIndex = faces[ offset ++ ]; - face.materialIndex = materialIndex; - - } - - // to get face <=> uv index correspondence - - fi = geometry.faces.length; - - if ( hasFaceVertexUv ) { - - for ( i = 0; i < nUvLayers; i++ ) { - - uvLayer = json.uvs[ i ]; - - geometry.faceVertexUvs[ i ][ fi ] = []; - - for ( j = 0; j < 3; j ++ ) { - - uvIndex = faces[ offset ++ ]; - - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; - - uv = new THREE.Vector2( u, v ); - - geometry.faceVertexUvs[ i ][ fi ].push( uv ); - - } - - } - - } - - if ( hasFaceNormal ) { - - normalIndex = faces[ offset ++ ] * 3; - - face.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); - - } - - if ( hasFaceVertexNormal ) { - - for ( i = 0; i < 3; i++ ) { - - normalIndex = faces[ offset ++ ] * 3; - - normal = new THREE.Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); - - face.vertexNormals.push( normal ); - - } - - } - - - if ( hasFaceColor ) { - - colorIndex = faces[ offset ++ ]; - face.color.setHex( colors[ colorIndex ] ); - - } - - - if ( hasFaceVertexColor ) { - - for ( i = 0; i < 3; i++ ) { - - colorIndex = faces[ offset ++ ]; - face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) ); - - } - - } - - geometry.faces.push( face ); - - } - - } - - }; - - function parseSkin() { - - if ( json.skinWeights ) { - - for ( var i = 0, l = json.skinWeights.length; i < l; i += 2 ) { - - var x = json.skinWeights[ i ]; - var y = json.skinWeights[ i + 1 ]; - var z = 0; - var w = 0; - - geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) ); - - } - - } - - if ( json.skinIndices ) { - - for ( var i = 0, l = json.skinIndices.length; i < l; i += 2 ) { - - var a = json.skinIndices[ i ]; - var b = json.skinIndices[ i + 1 ]; - var c = 0; - var d = 0; - - geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) ); - - } - - } - - geometry.bones = json.bones; - - if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { - - THREE.onwarning( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + - geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); - - } - - - // could change this to json.animations[0] or remove completely - - geometry.animation = json.animation; - geometry.animations = json.animations; - - }; - - function parseMorphing( scale ) { - - if ( json.morphTargets !== undefined ) { - - var i, l, v, vl, dstVertices, srcVertices; - - for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) { - - geometry.morphTargets[ i ] = {}; - geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; - geometry.morphTargets[ i ].vertices = []; - - dstVertices = geometry.morphTargets[ i ].vertices; - srcVertices = json.morphTargets [ i ].vertices; - - for( v = 0, vl = srcVertices.length; v < vl; v += 3 ) { - - var vertex = new THREE.Vector3(); - vertex.x = srcVertices[ v ] * scale; - vertex.y = srcVertices[ v + 1 ] * scale; - vertex.z = srcVertices[ v + 2 ] * scale; - - dstVertices.push( vertex ); - - } - - } - - } - - if ( json.morphColors !== undefined ) { - - var i, l, c, cl, dstColors, srcColors, color; - - for ( i = 0, l = json.morphColors.length; i < l; i++ ) { - - geometry.morphColors[ i ] = {}; - geometry.morphColors[ i ].name = json.morphColors[ i ].name; - geometry.morphColors[ i ].colors = []; - - dstColors = geometry.morphColors[ i ].colors; - srcColors = json.morphColors [ i ].colors; - - for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) { - - color = new THREE.Color( 0xffaa00 ); - color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] ); - dstColors.push( color ); - - } - - } - - } - - }; - - if ( json.materials === undefined ) { - - return { geometry: geometry }; - - } else { - - var materials = this.initMaterials( json.materials, texturePath ); - - if ( this.needsTangents( materials ) ) { - - geometry.computeTangents(); - - } - - return { geometry: geometry, materials: materials }; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.LoadingManager = function ( onLoad, onProgress, onError ) { - - var scope = this; - - var loaded = 0, total = 0; - - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; - - this.itemStart = function ( url ) { - - total ++; - - }; - - this.itemEnd = function ( url ) { - - loaded ++; - - if ( scope.onProgress !== undefined ) { - - scope.onProgress( url, loaded, total ); - - } - - if ( loaded === total && scope.onLoad !== undefined ) { - - scope.onLoad(); - - } - - }; - -}; - -THREE.DefaultLoadingManager = new THREE.LoadingManager(); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.BufferGeometryLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.BufferGeometryLoader.prototype = { - - constructor: THREE.BufferGeometryLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader(); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - }, - - parse: function ( json ) { - - var geometry = new THREE.BufferGeometry(); - - var attributes = json.attributes; - var offsets = json.offsets; - var boundingSphere = json.boundingSphere; - - for ( var key in attributes ) { - - var attribute = attributes[ key ]; - - geometry.attributes[ key ] = { - itemSize: attribute.itemSize, - array: new self[ attribute.type ]( attribute.array ) - } - - } - - if ( offsets !== undefined ) { - - geometry.offsets = JSON.parse( JSON.stringify( offsets ) ); - - } - - if ( boundingSphere !== undefined ) { - - geometry.boundingSphere = new THREE.Sphere( - new THREE.Vector3().fromArray( boundingSphere.center !== undefined ? boundingSphere.center : [ 0, 0, 0 ] ), - boundingSphere.radius - ); - - } - - return geometry; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Geometry2Loader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.Geometry2Loader.prototype = { - - constructor: THREE.Geometry2Loader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader(); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - }, - - parse: function ( json ) { - - var geometry = new THREE.Geometry2( json.vertices.length / 3 ); - - var attributes = [ 'vertices', 'normals', 'uvs' ]; - var boundingSphere = json.boundingSphere; - - for ( var key in attributes ) { - - var attribute = attributes[ key ]; - geometry[ attribute ].set( json[ attribute ] ); - - } - - if ( boundingSphere !== undefined ) { - - geometry.boundingSphere = new THREE.Sphere( - new THREE.Vector3().fromArray( boundingSphere.center !== undefined ? boundingSphere.center : [ 0, 0, 0 ] ), - boundingSphere.radius - ); - - } - - return geometry; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.MaterialLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.MaterialLoader.prototype = { - - constructor: THREE.MaterialLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader(); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - }, - - parse: function ( json ) { - - var material = new THREE[ json.type ]; - - if ( json.color !== undefined ) material.color.setHex( json.color ); - if ( json.ambient !== undefined ) material.ambient.setHex( json.ambient ); - if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); - if ( json.specular !== undefined ) material.specular.setHex( json.specular ); - if ( json.falloff !== undefined ) material.falloff = json.falloff; - if ( json.falloffColor !== undefined ) material.falloffColor.setHex( json.falloffColor ); - if ( json.roughness !== undefined ) material.roughness = json.roughness; - if ( json.metallic !== undefined ) material.metallic = json.metallic; - if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat; - if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness; - if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy; - if ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation; - if ( json.translucency !== undefined ) material.translucency.setHex( json.translucency ); - if ( json.translucencyNormalAlpha !== undefined ) material.translucencyNormalAlpha = json.translucencyNormalAlpha; - if ( json.translucencyNormalPower !== undefined ) material.translucencyNormalPower = json.translucencyNormalPower; - if ( json.translucencyViewAlpha !== undefined ) material.translucencyViewAlpha = json.translucencyViewAlpha; - if ( json.translucencyViewPower !== undefined ) material.translucencyViewPower = json.translucencyViewPower; - if ( json.shininess !== undefined ) material.shininess = json.shininess; - if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; - if ( json.blending !== undefined ) material.blending = json.blending; - if ( json.side !== undefined ) material.side = json.side; - if ( json.opacity !== undefined ) material.opacity = json.opacity; - if ( json.transparent !== undefined ) material.transparent = json.transparent; - if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; - - if ( json.materials !== undefined ) { - - for ( var i = 0, l = json.materials.length; i < l; i ++ ) { - - material.materials.push( this.parse( json.materials[ i ] ) ); - - } - - } - - return material; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.ObjectLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.ObjectLoader.prototype = { - - constructor: THREE.ObjectLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader( scope.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - }, - - parse: function ( json ) { - - var geometries = this.parseGeometries( json.geometries ); - var materials = this.parseMaterials( json.materials ); - var object = this.parseObject( json.object, geometries, materials ); - - return object; - - }, - - parseGeometries: function ( json ) { - - var geometries = {}; - - if ( json !== undefined ) { - - var geometryLoader = new THREE.JSONLoader(); - var geometry2Loader = new THREE.Geometry2Loader(); - var bufferGeometryLoader = new THREE.BufferGeometryLoader(); - - for ( var i = 0, l = json.length; i < l; i ++ ) { - - var geometry; - var data = json[ i ]; - - switch ( data.type ) { - - case 'PlaneGeometry': - - geometry = new THREE.PlaneGeometry( - data.width, - data.height, - data.widthSegments, - data.heightSegments - ); - - break; - - case 'BoxGeometry': - case 'CubeGeometry': // DEPRECATED - - geometry = new THREE.BoxGeometry( - data.width, - data.height, - data.depth, - data.widthSegments, - data.heightSegments, - data.depthSegments - ); - - break; - - case 'CircleGeometry': - - geometry = new THREE.CircleGeometry( - data.radius, - data.segments - ); - - break; - - case 'CylinderGeometry': - - geometry = new THREE.CylinderGeometry( - data.radiusTop, - data.radiusBottom, - data.height, - data.radialSegments, - data.heightSegments, - data.openEnded - ); - - break; - - case 'SphereGeometry': - - geometry = new THREE.SphereGeometry( - data.radius, - data.widthSegments, - data.heightSegments, - data.phiStart, - data.phiLength, - data.thetaStart, - data.thetaLength - ); - - break; - - case 'IcosahedronGeometry': - - geometry = new THREE.IcosahedronGeometry( - data.radius, - data.detail - ); - - break; - - case 'TorusGeometry': - - geometry = new THREE.TorusGeometry( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.arc - ); - - break; - - case 'TorusKnotGeometry': - - geometry = new THREE.TorusKnotGeometry( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.p, - data.q, - data.heightScale - ); - - break; - - case 'BufferGeometry': - - geometry = bufferGeometryLoader.parse( data.data ); - - break; - - case 'Geometry2': - - geometry = geometry2Loader.parse( data.data ); - - break; - - case 'Geometry': - - geometry = geometryLoader.parse( data.data ).geometry; - - break; - - } - - geometry.uuid = data.uuid; - - if ( data.name !== undefined ) geometry.name = data.name; - - geometries[ data.uuid ] = geometry; - - } - - } - - return geometries; - - }, - - parseMaterials: function ( json ) { - - var materials = {}; - - if ( json !== undefined ) { - - var loader = new THREE.MaterialLoader(); - - for ( var i = 0, l = json.length; i < l; i ++ ) { - - var data = json[ i ]; - var material = loader.parse( data ); - - material.uuid = data.uuid; - - if ( data.name !== undefined ) material.name = data.name; - - materials[ data.uuid ] = material; - - } - - } - - return materials; - - }, - - parseObject: function () { - - var matrix = new THREE.Matrix4(); - - return function ( data, geometries, materials ) { - - var object; - - switch ( data.type ) { - - case 'Scene': - - object = new THREE.Scene(); - - break; - - case 'PerspectiveCamera': - - object = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); - - break; - - case 'OrthographicCamera': - - object = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); - - break; - - case 'AmbientLight': - - object = new THREE.AmbientLight( data.color ); - - break; - - case 'DirectionalLight': - - object = new THREE.DirectionalLight( data.color, data.intensity ); - - break; - - case 'PointLight': - - object = new THREE.PointLight( data.color, data.intensity, data.distance, data.decay, data.physicalFalloff ); - - break; - - case 'SpotLight': - - object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent, data.decay, data.physicalFalloff ); - - break; - - case 'HemisphereLight': - - object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity ); - - break; - - case 'AreaLight': - - object = new THREE.AreaLight( data.color, data.intensity, data.distance, data.decayExponent, data.decay, data.physicalFalloff ); - object.width = data.width || 1; - object.height = data.height || 1; - - break; - - case 'Mesh': - - var geometry = geometries[ data.geometry ]; - var material = materials[ data.material ]; - - if ( geometry === undefined ) { - - THREE.onerror( 'THREE.ObjectLoader: Undefined geometry ' + data.geometry ); - - } - - if ( material === undefined ) { - - THREE.onerror( 'THREE.ObjectLoader: Undefined material ' + data.material ); - - } - - object = new THREE.Mesh( geometry, material ); - - break; - - case 'Sprite': - - var material = materials[ data.material ]; - - if ( material === undefined ) { - - THREE.onerror( 'THREE.ObjectLoader: Undefined material ' + data.material ); - - } - - object = new THREE.Sprite( material ); - - break; - - default: - - object = new THREE.Object3D(); - - } - - object.uuid = data.uuid; - - if ( data.name !== undefined ) object.name = data.name; - if ( data.matrix !== undefined ) { - - matrix.fromArray( data.matrix ); - matrix.decompose( object.position, object.quaternion, object.scale ); - - } else { - - if ( data.position !== undefined ) object.position.fromArray( data.position ); - if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); - if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); - - } - - if ( data.visible !== undefined ) object.visible = data.visible; - if ( data.userData !== undefined ) object.userData = data.userData; - - if ( data.children !== undefined ) { - - for ( var child in data.children ) { - - object.add( this.parseObject( data.children[ child ], geometries, materials ) ); - - } - - } - - return object; - - } - - }() - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.SceneLoader = function () { - - this.onLoadStart = function () {}; - this.onLoadProgress = function() {}; - this.onLoadComplete = function () {}; - - this.callbackSync = function () {}; - this.callbackProgress = function () {}; - - this.geometryHandlers = {}; - this.hierarchyHandlers = {}; - - this.addGeometryHandler( "ascii", THREE.JSONLoader ); - -}; - -THREE.SceneLoader.prototype = { - - constructor: THREE.SceneLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader( scope.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( text ) { - - scope.parse( JSON.parse( text ), onLoad, url ); - - } ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - }, - - addGeometryHandler: function ( typeID, loaderClass ) { - - this.geometryHandlers[ typeID ] = { "loaderClass": loaderClass }; - - }, - - addHierarchyHandler: function ( typeID, loaderClass ) { - - this.hierarchyHandlers[ typeID ] = { "loaderClass": loaderClass }; - - }, - - parse: function ( json, callbackFinished, url ) { - - var scope = this; - - var urlBase = THREE.Loader.prototype.extractUrlBase( url ); - - var geometry, material, camera, fog, - texture, images, color, - light, hex, intensity, - counter_models, counter_textures, - total_models, total_textures, - result; - - var target_array = []; - - var data = json; - - // async geometry loaders - - for ( var typeID in this.geometryHandlers ) { - - var loaderClass = this.geometryHandlers[ typeID ][ "loaderClass" ]; - this.geometryHandlers[ typeID ][ "loaderObject" ] = new loaderClass(); - - } - - // async hierachy loaders - - for ( var typeID in this.hierarchyHandlers ) { - - var loaderClass = this.hierarchyHandlers[ typeID ][ "loaderClass" ]; - this.hierarchyHandlers[ typeID ][ "loaderObject" ] = new loaderClass(); - - } - - counter_models = 0; - counter_textures = 0; - - result = { - - scene: new THREE.Scene(), - geometries: {}, - face_materials: {}, - materials: {}, - textures: {}, - objects: {}, - cameras: {}, - lights: {}, - fogs: {}, - empties: {}, - groups: {} - - }; - - if ( data.transform ) { - - var position = data.transform.position, - rotation = data.transform.rotation, - scale = data.transform.scale; - - if ( position ) { - - result.scene.position.fromArray( position ); - - } - - if ( rotation ) { - - result.scene.rotation.fromArray( rotation ); - - } - - if ( scale ) { - - result.scene.scale.fromArray( scale ); - - } - - if ( position || rotation || scale ) { - - result.scene.updateMatrix(); - result.scene.updateMatrixWorld(); - - } - - } - - function get_url( source_url, url_type ) { - - if ( url_type == "relativeToHTML" ) { - - return source_url; - - } else { - - return urlBase + source_url; - - } - - }; - - // toplevel loader function, delegates to handle_children - - function handle_objects() { - - handle_children( result.scene, data.objects ); - - } - - // handle all the children from the loaded json and attach them to given parent - - function handle_children( parent, children ) { - - var mat, dst, pos, rot, scl, quat; - - for ( var objID in children ) { - - // check by id if child has already been handled, - // if not, create new object - - var object = result.objects[ objID ]; - var objJSON = children[ objID ]; - - if ( object === undefined ) { - - // meshes - - if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) { - - if ( objJSON.loading === undefined ) { - - var reservedTypes = { - "type": 1, "url": 1, "material": 1, - "position": 1, "rotation": 1, "scale" : 1, - "visible": 1, "children": 1, "userData": 1, - "skin": 1, "morph": 1, "mirroredLoop": 1, "duration": 1 - }; - - var loaderParameters = {}; - - for ( var parType in objJSON ) { - - if ( ! ( parType in reservedTypes ) ) { - - loaderParameters[ parType ] = objJSON[ parType ]; - - } - - } - - material = result.materials[ objJSON.material ]; - - objJSON.loading = true; - - var loader = scope.hierarchyHandlers[ objJSON.type ][ "loaderObject" ]; - - // ColladaLoader - - if ( loader.options ) { - - loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ) ); - - // UTF8Loader - // OBJLoader - - } else { - - loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ), loaderParameters ); - - } - - } - - } else if ( objJSON.geometry !== undefined ) { - - geometry = result.geometries[ objJSON.geometry ]; - - // geometry already loaded - - if ( geometry ) { - - var needsTangents = false; - - material = result.materials[ objJSON.material ]; - needsTangents = material instanceof THREE.ShaderMaterial; - - pos = objJSON.position; - rot = objJSON.rotation; - scl = objJSON.scale; - mat = objJSON.matrix; - quat = objJSON.quaternion; - - // use materials from the model file - // if there is no material specified in the object - - if ( ! objJSON.material ) { - - material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); - - } - - // use materials from the model file - // if there is just empty face material - // (must create new material as each model has its own face material) - - if ( ( material instanceof THREE.MeshFaceMaterial ) && material.materials.length === 0 ) { - - material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); - - } - - if ( material instanceof THREE.MeshFaceMaterial ) { - - for ( var i = 0; i < material.materials.length; i ++ ) { - - needsTangents = needsTangents || ( material.materials[ i ] instanceof THREE.ShaderMaterial ); - - } - - } - - if ( needsTangents ) { - - geometry.computeTangents(); - - } - - if ( objJSON.skin ) { - - object = new THREE.SkinnedMesh( geometry, material ); - - } else if ( objJSON.morph ) { - - object = new THREE.MorphAnimMesh( geometry, material ); - - if ( objJSON.duration !== undefined ) { - - object.duration = objJSON.duration; - - } - - if ( objJSON.time !== undefined ) { - - object.time = objJSON.time; - - } - - if ( objJSON.mirroredLoop !== undefined ) { - - object.mirroredLoop = objJSON.mirroredLoop; - - } - - if ( material.morphNormals ) { - - geometry.computeMorphNormals(); - - } - - } else { - - object = new THREE.Mesh( geometry, material ); - - } - - object.name = objID; - - if ( mat ) { - - object.matrixAutoUpdate = false; - object.matrix.set( - mat[0], mat[1], mat[2], mat[3], - mat[4], mat[5], mat[6], mat[7], - mat[8], mat[9], mat[10], mat[11], - mat[12], mat[13], mat[14], mat[15] - ); - - } else { - - object.position.fromArray( pos ); - - if ( quat ) { - - object.quaternion.fromArray( quat ); - - } else { - - object.rotation.fromArray( rot ); - - } - - object.scale.fromArray( scl ); - - } - - object.visible = objJSON.visible; - object.castShadow = objJSON.castShadow; - object.receiveShadow = objJSON.receiveShadow; - - parent.add( object ); - - result.objects[ objID ] = object; - - } - - // lights - - } else if ( objJSON.type === "AmbientLight" || objJSON.type === "PointLight" || - objJSON.type === "DirectionalLight" || objJSON.type === "SpotLight" || - objJSON.type === "HemisphereLight" || objJSON.type === "AreaLight" ) { - - var color = objJSON.color; - var intensity = objJSON.intensity; - var distance = objJSON.distance; - var position = objJSON.position; - var rotation = objJSON.rotation; - - switch ( objJSON.type ) { - - case 'AmbientLight': - light = new THREE.AmbientLight( color ); - break; - - case 'PointLight': - light = new THREE.PointLight( color, intensity, distance ); - light.position.fromArray( position ); - break; - - case 'DirectionalLight': - light = new THREE.DirectionalLight( color, intensity ); - light.position.fromArray( objJSON.direction ); - break; - - case 'SpotLight': - light = new THREE.SpotLight( color, intensity, distance, 1 ); - light.angle = objJSON.angle; - light.position.fromArray( position ); - light.target.set( position[ 0 ], position[ 1 ] - distance, position[ 2 ] ); - light.target.applyEuler( new THREE.Euler( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ], 'XYZ' ) ); - break; - - case 'HemisphereLight': - light = new THREE.DirectionalLight( color, intensity, distance ); - light.target.set( position[ 0 ], position[ 1 ] - distance, position[ 2 ] ); - light.target.applyEuler( new THREE.Euler( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ], 'XYZ' ) ); - break; - - case 'AreaLight': - light = new THREE.AreaLight(color, intensity); - light.position.fromArray( position ); - light.width = objJSON.size; - light.height = objJSON.size_y; - break; - - } - - parent.add( light ); - - light.name = objID; - result.lights[ objID ] = light; - result.objects[ objID ] = light; - - // cameras - - } else if ( objJSON.type === "PerspectiveCamera" || objJSON.type === "OrthographicCamera" ) { - - pos = objJSON.position; - rot = objJSON.rotation; - quat = objJSON.quaternion; - - if ( objJSON.type === "PerspectiveCamera" ) { - - camera = new THREE.PerspectiveCamera( objJSON.fov, objJSON.aspect, objJSON.near, objJSON.far ); - - } else if ( objJSON.type === "OrthographicCamera" ) { - - camera = new THREE.OrthographicCamera( objJSON.left, objJSON.right, objJSON.top, objJSON.bottom, objJSON.near, objJSON.far ); - - } - - camera.name = objID; - camera.position.fromArray( pos ); - - if ( quat !== undefined ) { - - camera.quaternion.fromArray( quat ); - - } else if ( rot !== undefined ) { - - camera.rotation.fromArray( rot ); - - } - - parent.add( camera ); - - result.cameras[ objID ] = camera; - result.objects[ objID ] = camera; - - // pure Object3D - - } else { - - pos = objJSON.position; - rot = objJSON.rotation; - scl = objJSON.scale; - quat = objJSON.quaternion; - - object = new THREE.Object3D(); - object.name = objID; - object.position.fromArray( pos ); - - if ( quat ) { - - object.quaternion.fromArray( quat ); - - } else { - - object.rotation.fromArray( rot ); - - } - - object.scale.fromArray( scl ); - object.visible = ( objJSON.visible !== undefined ) ? objJSON.visible : false; - - parent.add( object ); - - result.objects[ objID ] = object; - result.empties[ objID ] = object; - - } - - if ( object ) { - - if ( objJSON.userData !== undefined ) { - - for ( var key in objJSON.userData ) { - - var value = objJSON.userData[ key ]; - object.userData[ key ] = value; - - } - - } - - if ( objJSON.groups !== undefined ) { - - for ( var i = 0; i < objJSON.groups.length; i ++ ) { - - var groupID = objJSON.groups[ i ]; - - if ( result.groups[ groupID ] === undefined ) { - - result.groups[ groupID ] = []; - - } - - result.groups[ groupID ].push( objID ); - - } - - } - - } - - } - - if ( object !== undefined && objJSON.children !== undefined ) { - - handle_children( object, objJSON.children ); - - } - - } - - }; - - function handle_mesh( geo, mat, id ) { - - result.geometries[ id ] = geo; - result.face_materials[ id ] = mat; - handle_objects(); - - }; - - function handle_hierarchy( node, id, parent, material, obj ) { - - var p = obj.position; - var r = obj.rotation; - var q = obj.quaternion; - var s = obj.scale; - - node.position.fromArray( p ); - - if ( q ) { - - node.quaternion.fromArray( q ); - - } else { - - node.rotation.fromArray( r ); - - } - - node.scale.fromArray( s ); - - // override children materials - // if object material was specified in JSON explicitly - - if ( material ) { - - node.traverse( function ( child ) { - - child.material = material; - - } ); - - } - - // override children visibility - // with root node visibility as specified in JSON - - var visible = ( obj.visible !== undefined ) ? obj.visible : true; - - node.traverse( function ( child ) { - - child.visible = visible; - - } ); - - parent.add( node ); - - node.name = id; - - result.objects[ id ] = node; - handle_objects(); - - }; - - function create_callback_geometry( id ) { - - return function ( geo, mat ) { - - geo.name = id; - - handle_mesh( geo, mat, id ); - - counter_models -= 1; - - scope.onLoadComplete(); - - async_callback_gate(); - - } - - }; - - function create_callback_hierachy( id, parent, material, obj ) { - - return function ( event ) { - - var result; - - // loaders which use EventDispatcher - - if ( event.content ) { - - result = event.content; - - // ColladaLoader - - } else if ( event.dae ) { - - result = event.scene; - - - // UTF8Loader - - } else { - - result = event; - - } - - handle_hierarchy( result, id, parent, material, obj ); - - counter_models -= 1; - - scope.onLoadComplete(); - - async_callback_gate(); - - } - - }; - - function create_callback_embed( id ) { - - return function ( geo, mat ) { - - geo.name = id; - - result.geometries[ id ] = geo; - result.face_materials[ id ] = mat; - - } - - }; - - function async_callback_gate() { - - var progress = { - - totalModels : total_models, - totalTextures : total_textures, - loadedModels : total_models - counter_models, - loadedTextures : total_textures - counter_textures - - }; - - scope.callbackProgress( progress, result ); - - scope.onLoadProgress(); - - if ( counter_models === 0 && counter_textures === 0 ) { - - finalize(); - callbackFinished( result ); - - } - - }; - - function finalize() { - - // take care of targets which could be asynchronously loaded objects - - for ( var i = 0; i < target_array.length; i ++ ) { - - var ta = target_array[ i ]; - - var target = result.objects[ ta.targetName ]; - - if ( target ) { - - ta.object.target = target; - - } else { - - // if there was error and target of specified name doesn't exist in the scene file - // create instead dummy target - // (target must be added to scene explicitly as parent is already added) - - ta.object.target = new THREE.Object3D(); - result.scene.add( ta.object.target ); - - } - - ta.object.target.userData.targetInverse = ta.object; - - } - - }; - - var callbackTexture = function ( count ) { - - counter_textures -= count; - async_callback_gate(); - - scope.onLoadComplete(); - - }; - - // must use this instead of just directly calling callbackTexture - // because of closure in the calling context loop - - var generateTextureCallback = function ( count ) { - - return function () { - - callbackTexture( count ); - - }; - - }; - - function traverse_json_hierarchy( objJSON, callback ) { - - callback( objJSON ); - - if ( objJSON.children !== undefined ) { - - for ( var objChildID in objJSON.children ) { - - traverse_json_hierarchy( objJSON.children[ objChildID ], callback ); - - } - - } - - }; - - // first go synchronous elements - - // fogs - - var fogID, fogJSON; - - for ( fogID in data.fogs ) { - - fogJSON = data.fogs[ fogID ]; - - if ( fogJSON.type === "linear" ) { - - fog = new THREE.Fog( 0x000000, fogJSON.near, fogJSON.far ); - - } else if ( fogJSON.type === "exp2" ) { - - fog = new THREE.FogExp2( 0x000000, fogJSON.density ); - - } - - color = fogJSON.color; - fog.color.setRGB( color[0], color[1], color[2] ); - - result.fogs[ fogID ] = fog; - - } - - // now come potentially asynchronous elements - - // geometries - - // count how many geometries will be loaded asynchronously - - var geoID, geoJSON; - - for ( geoID in data.geometries ) { - - geoJSON = data.geometries[ geoID ]; - - if ( geoJSON.type in this.geometryHandlers ) { - - counter_models += 1; - - scope.onLoadStart(); - - } - - } - - // count how many hierarchies will be loaded asynchronously - - for ( var objID in data.objects ) { - - traverse_json_hierarchy( data.objects[ objID ], function ( objJSON ) { - - if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) { - - counter_models += 1; - - scope.onLoadStart(); - - } - - }); - - } - - total_models = counter_models; - - for ( geoID in data.geometries ) { - - geoJSON = data.geometries[ geoID ]; - - if ( geoJSON.type === "cube" ) { - - geometry = new THREE.BoxGeometry( geoJSON.width, geoJSON.height, geoJSON.depth, geoJSON.widthSegments, geoJSON.heightSegments, geoJSON.depthSegments ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; - - } else if ( geoJSON.type === "plane" ) { - - geometry = new THREE.PlaneGeometry( geoJSON.width, geoJSON.height, geoJSON.widthSegments, geoJSON.heightSegments ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; - - } else if ( geoJSON.type === "sphere" ) { - - geometry = new THREE.SphereGeometry( geoJSON.radius, geoJSON.widthSegments, geoJSON.heightSegments ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; - - } else if ( geoJSON.type === "cylinder" ) { - - geometry = new THREE.CylinderGeometry( geoJSON.topRad, geoJSON.botRad, geoJSON.height, geoJSON.radSegs, geoJSON.heightSegs ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; - - } else if ( geoJSON.type === "torus" ) { - - geometry = new THREE.TorusGeometry( geoJSON.radius, geoJSON.tube, geoJSON.segmentsR, geoJSON.segmentsT ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; - - } else if ( geoJSON.type === "icosahedron" ) { - - geometry = new THREE.IcosahedronGeometry( geoJSON.radius, geoJSON.subdivisions ); - geometry.name = geoID; - result.geometries[ geoID ] = geometry; - - } else if ( geoJSON.type in this.geometryHandlers ) { - - var loaderParameters = {}; - - for ( var parType in geoJSON ) { - - if ( parType !== "type" && parType !== "url" ) { - - loaderParameters[ parType ] = geoJSON[ parType ]; - - } - - } - - var loader = this.geometryHandlers[ geoJSON.type ][ "loaderObject" ]; - loader.load( get_url( geoJSON.url, data.urlBaseType ), create_callback_geometry( geoID ), loaderParameters ); - - } else if ( geoJSON.type === "embedded" ) { - - var modelJson = data.embeds[ geoJSON.id ], - texture_path = ""; - - // pass metadata along to jsonLoader so it knows the format version - - modelJson.metadata = data.metadata; - - if ( modelJson ) { - - var jsonLoader = this.geometryHandlers[ "ascii" ][ "loaderObject" ]; - var model = jsonLoader.parse( modelJson, texture_path ); - create_callback_embed( geoID )( model.geometry, model.materials ); - - } - - } - - } - - // textures - - // count how many textures will be loaded asynchronously - - var textureID, textureJSON; - - for ( textureID in data.textures ) { - - textureJSON = data.textures[ textureID ]; - - if ( textureJSON.url instanceof Array ) { - - counter_textures += textureJSON.url.length; - - for( var n = 0; n < textureJSON.url.length; n ++ ) { - - scope.onLoadStart(); - - } - - } else { - - counter_textures += 1; - - scope.onLoadStart(); - - } - - } - - total_textures = counter_textures; - - for ( textureID in data.textures ) { - - textureJSON = data.textures[ textureID ]; - - if ( textureJSON.mapping !== undefined && THREE[ textureJSON.mapping ] !== undefined ) { - - textureJSON.mapping = new THREE[ textureJSON.mapping ](); - - } - - if ( textureJSON.url instanceof Array ) { - - var count = textureJSON.url.length; - var url_array = []; - - for( var i = 0; i < count; i ++ ) { - - url_array[ i ] = get_url( textureJSON.url[ i ], data.urlBaseType ); - - } - - var isCompressed = /\.dds$/i.test( url_array[ 0 ] ); - - if ( isCompressed ) { - - texture = THREE.ImageUtils.loadCompressedTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); - - } else { - - texture = THREE.ImageUtils.loadTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); - - } - - } else { - - var isCompressed = /\.dds$/i.test( textureJSON.url ); - var fullUrl = get_url( textureJSON.url, data.urlBaseType ); - var textureCallback = generateTextureCallback( 1 ); - - if ( isCompressed ) { - - texture = THREE.ImageUtils.loadCompressedTexture( fullUrl, textureJSON.mapping, textureCallback ); - - } else { - - texture = THREE.ImageUtils.loadTexture( fullUrl, textureJSON.mapping, textureCallback ); - - } - - if ( THREE[ textureJSON.minFilter ] !== undefined ) - texture.minFilter = THREE[ textureJSON.minFilter ]; - - if ( THREE[ textureJSON.magFilter ] !== undefined ) - texture.magFilter = THREE[ textureJSON.magFilter ]; - - if ( textureJSON.anisotropy ) texture.anisotropy = textureJSON.anisotropy; - - if ( textureJSON.repeat ) { - - texture.repeat.set( textureJSON.repeat[ 0 ], textureJSON.repeat[ 1 ] ); - - if ( textureJSON.repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping; - if ( textureJSON.repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping; - - } - - if ( textureJSON.offset ) { - - texture.offset.set( textureJSON.offset[ 0 ], textureJSON.offset[ 1 ] ); - - } - - // handle wrap after repeat so that default repeat can be overriden - - if ( textureJSON.wrap ) { - - var wrapMap = { - "repeat": THREE.RepeatWrapping, - "mirror": THREE.MirroredRepeatWrapping - } - - if ( wrapMap[ textureJSON.wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ textureJSON.wrap[ 0 ] ]; - if ( wrapMap[ textureJSON.wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ textureJSON.wrap[ 1 ] ]; - - } - - } - - result.textures[ textureID ] = texture; - - } - - // materials - - var matID, matJSON; - var parID; - - for ( matID in data.materials ) { - - matJSON = data.materials[ matID ]; - - for ( parID in matJSON.parameters ) { - - if ( parID === "envMap" || parID === "map" || parID === "lightMap" || parID === "bumpMap" ) { - - matJSON.parameters[ parID ] = result.textures[ matJSON.parameters[ parID ] ]; - - } else if ( parID === "shading" ) { - - matJSON.parameters[ parID ] = ( matJSON.parameters[ parID ] === "flat" ) ? THREE.FlatShading : THREE.SmoothShading; - - } else if ( parID === "side" ) { - - if ( matJSON.parameters[ parID ] == "double" ) { - - matJSON.parameters[ parID ] = THREE.DoubleSide; - - } else if ( matJSON.parameters[ parID ] == "back" ) { - - matJSON.parameters[ parID ] = THREE.BackSide; - - } else { - - matJSON.parameters[ parID ] = THREE.FrontSide; - - } - - } else if ( parID === "blending" ) { - - matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.NormalBlending; - - } else if ( parID === "combine" ) { - - matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.MultiplyOperation; - - } else if ( parID === "vertexColors" ) { - - if ( matJSON.parameters[ parID ] == "face" ) { - - matJSON.parameters[ parID ] = THREE.FaceColors; - - // default to vertex colors if "vertexColors" is anything else face colors or 0 / null / false - - } else if ( matJSON.parameters[ parID ] ) { - - matJSON.parameters[ parID ] = THREE.VertexColors; - - } - - } else if ( parID === "wrapRGB" ) { - - var v3 = matJSON.parameters[ parID ]; - matJSON.parameters[ parID ] = new THREE.Vector3( v3[ 0 ], v3[ 1 ], v3[ 2 ] ); - - } - - } - - if ( matJSON.parameters.opacity !== undefined && matJSON.parameters.opacity < 1.0 ) { - - matJSON.parameters.transparent = true; - - } - - if ( matJSON.parameters.normalMap ) { - - var shader = THREE.ShaderLib[ "normalmap" ]; - var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); - - var diffuse = matJSON.parameters.color; - var specular = matJSON.parameters.specular; - var ambient = matJSON.parameters.ambient; - var shininess = matJSON.parameters.shininess; - - uniforms[ "tNormal" ].value = result.textures[ matJSON.parameters.normalMap ]; - - if ( matJSON.parameters.normalScale ) { - - uniforms[ "uNormalScale" ].value.set( matJSON.parameters.normalScale[ 0 ], matJSON.parameters.normalScale[ 1 ] ); - - } - - if ( matJSON.parameters.map ) { - - uniforms[ "tDiffuse" ].value = matJSON.parameters.map; - uniforms[ "enableDiffuse" ].value = true; - - } - - if ( matJSON.parameters.envMap ) { - - uniforms[ "tCube" ].value = matJSON.parameters.envMap; - uniforms[ "enableReflection" ].value = true; - uniforms[ "reflectivity" ].value = matJSON.parameters.reflectivity; - - } - - if ( matJSON.parameters.lightMap ) { - - uniforms[ "tAO" ].value = matJSON.parameters.lightMap; - uniforms[ "enableAO" ].value = true; - - } - - if ( matJSON.parameters.specularMap ) { - - uniforms[ "tSpecular" ].value = result.textures[ matJSON.parameters.specularMap ]; - uniforms[ "enableSpecular" ].value = true; - - } - - if ( matJSON.parameters.displacementMap ) { - - uniforms[ "tDisplacement" ].value = result.textures[ matJSON.parameters.displacementMap ]; - uniforms[ "enableDisplacement" ].value = true; - - uniforms[ "uDisplacementBias" ].value = matJSON.parameters.displacementBias; - uniforms[ "uDisplacementScale" ].value = matJSON.parameters.displacementScale; - - } - - uniforms[ "diffuse" ].value.setHex( diffuse ); - uniforms[ "specular" ].value.setHex( specular ); - uniforms[ "ambient" ].value.setHex( ambient ); - - uniforms[ "shininess" ].value = shininess; - - if ( matJSON.parameters.opacity ) { - - uniforms[ "opacity" ].value = matJSON.parameters.opacity; - - } - - var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; - - material = new THREE.ShaderMaterial( parameters ); - - } else { - - material = new THREE[ matJSON.type ]( matJSON.parameters ); - - } - - material.name = matID; - - result.materials[ matID ] = material; - - } - - // second pass through all materials to initialize MeshFaceMaterials - // that could be referring to other materials out of order - - for ( matID in data.materials ) { - - matJSON = data.materials[ matID ]; - - if ( matJSON.parameters.materials ) { - - var materialArray = []; - - for ( var i = 0; i < matJSON.parameters.materials.length; i ++ ) { - - var label = matJSON.parameters.materials[ i ]; - materialArray.push( result.materials[ label ] ); - - } - - result.materials[ matID ].materials = materialArray; - - } - - } - - // objects ( synchronous init of procedural primitives ) - - handle_objects(); - - // defaults - - if ( result.cameras && data.defaults.camera ) { - - result.currentCamera = result.cameras[ data.defaults.camera ]; - - } - - if ( result.fogs && data.defaults.fog ) { - - result.scene.fog = result.fogs[ data.defaults.fog ]; - - } - - // synchronous callback - - scope.callbackSync( result ); - - // just in case there are no async elements - - async_callback_gate(); - - } - -} - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.TextureLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.TextureLoader.prototype = { - - constructor: THREE.TextureLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.ImageLoader( scope.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.load( url, function ( image ) { - - var texture = new THREE.Texture( image ); - texture.needsUpdate = true; - - if ( onLoad !== undefined ) { - - onLoad( texture ); - - } - - } ); - - }, - - setCrossOrigin: function ( value ) { - - this.crossOrigin = value; - - } - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Material = function () { - - this.id = THREE.MaterialIdCount ++; - this.uuid = THREE.Math.generateUUID(); - - this.name = ''; - - this.side = THREE.FrontSide; - - this.opacity = 1; - this.transparent = false; - - this.blending = THREE.NormalBlending; - - this.blendSrc = THREE.SrcAlphaFactor; - this.blendDst = THREE.OneMinusSrcAlphaFactor; - this.blendEquation = THREE.AddEquation; - - this.depthTest = true; - this.depthWrite = true; - - this.polygonOffset = false; - this.polygonOffsetFactor = 0; - this.polygonOffsetUnits = 0; - - this.alphaTest = 0; - - this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer - - this.visible = true; - - this.needsUpdate = true; - -}; - -THREE.Material.prototype = { - - constructor: THREE.Material, - - setValues: function ( values ) { - - if ( values === undefined ) return; - - for ( var key in values ) { - - var newValue = values[ key ]; - - if ( newValue === undefined ) { - - THREE.onwarning( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); - continue; - - } - - if ( key in this ) { - - var currentValue = this[ key ]; - - if ( currentValue instanceof THREE.Color ) { - - currentValue.set( newValue ); - - } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) { - - currentValue.copy( newValue ); - - } else if ( key == 'overdraw') { - - // ensure overdraw is backwards-compatable with legacy boolean type - this[ key ] = Number(newValue); - - } else { - - this[ key ] = newValue; - - } - - } - - } - - }, - - clone: function ( material ) { - - if ( material === undefined ) material = new THREE.Material(); - - material.name = this.name; - - material.side = this.side; - - material.opacity = this.opacity; - material.transparent = this.transparent; - - material.blending = this.blending; - - material.blendSrc = this.blendSrc; - material.blendDst = this.blendDst; - material.blendEquation = this.blendEquation; - - material.depthTest = this.depthTest; - material.depthWrite = this.depthWrite; - - material.polygonOffset = this.polygonOffset; - material.polygonOffsetFactor = this.polygonOffsetFactor; - material.polygonOffsetUnits = this.polygonOffsetUnits; - - material.alphaTest = this.alphaTest; - - material.overdraw = this.overdraw; - - material.visible = this.visible; - - return material; - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.Material.prototype ); - -THREE.MaterialIdCount = 0; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * linewidth: , - * linecap: "round", - * linejoin: "round", - * - * vertexColors: - * - * fog: - * } - */ - -THREE.LineBasicMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); - - this.linewidth = 1; - this.linecap = 'round'; - this.linejoin = 'round'; - - this.vertexColors = false; - - this.fog = true; - - this.setValues( parameters ); - -}; - -THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.LineBasicMaterial.prototype.clone = function () { - - var material = new THREE.LineBasicMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.linewidth = this.linewidth; - material.linecap = this.linecap; - material.linejoin = this.linejoin; - - material.vertexColors = this.vertexColors; - - material.fog = this.fog; - - return material; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * linewidth: , - * - * scale: , - * dashSize: , - * gapSize: , - * - * vertexColors: - * - * fog: - * } - */ - -THREE.LineDashedMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); - - this.linewidth = 1; - - this.scale = 1; - this.dashSize = 3; - this.gapSize = 1; - - this.vertexColors = false; - - this.fog = true; - - this.setValues( parameters ); - -}; - -THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.LineDashedMaterial.prototype.clone = function () { - - var material = new THREE.LineDashedMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.linewidth = this.linewidth; - - material.scale = this.scale; - material.dashSize = this.dashSize; - material.gapSize = this.gapSize; - - material.vertexColors = this.vertexColors; - - material.fog = this.fog; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * - * specularMap: new THREE.Texture( ), - * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: , - * refractionRatio: , - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: , - * morphTargets: , - * - * fog: - * } - */ - -THREE.MeshBasicMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); // emissive - - this.map = null; - - this.lightMap = null; - - this.specularMap = null; - - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.fog = true; - - this.shading = THREE.SmoothShading; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.vertexColors = THREE.NoColors; - - this.skinning = false; - this.morphTargets = false; - - this.setValues( parameters ); - -}; - -THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.MeshBasicMaterial.prototype.clone = function () { - - var material = new THREE.MeshBasicMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.map = this.map; - - material.lightMap = this.lightMap; - - material.specularMap = this.specularMap; - - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; - - material.fog = this.fog; - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * ambient: , - * emissive: , - * opacity: , - * - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * - * specularMap: new THREE.Texture( ), - * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: , - * refractionRatio: , - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: , - * morphTargets: , - * morphNormals: , - * - * fog: - * } - */ - -THREE.MeshLambertMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); // diffuse - this.ambient = new THREE.Color( 0xffffff ); - this.emissive = new THREE.Color( 0x000000 ); - - this.wrapAround = false; - this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); - - this.map = null; - - this.lightMap = null; - - this.specularMap = null; - - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.fog = true; - - this.shading = THREE.SmoothShading; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.vertexColors = THREE.NoColors; - - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; - - this.setValues( parameters ); - -}; - -THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.MeshLambertMaterial.prototype.clone = function () { - - var material = new THREE.MeshLambertMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - material.ambient.copy( this.ambient ); - material.emissive.copy( this.emissive ); - - material.wrapAround = this.wrapAround; - material.wrapRGB.copy( this.wrapRGB ); - - material.map = this.map; - - material.lightMap = this.lightMap; - - material.specularMap = this.specularMap; - - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; - - material.fog = this.fog; - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * ambient: , - * emissive: , - * specular: , - * shininess: , - * opacity: , - * - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * - * bumpMap: new THREE.Texture( ), - * bumpScale: , - * - * normalMap: new THREE.Texture( ), - * normalScale: , - * - * specularMap: new THREE.Texture( ), - * - * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: , - * refractionRatio: , - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: , - * morphTargets: , - * morphNormals: , - * - * fog: - * } - */ - -THREE.MeshPhongMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); // diffuse - this.ambient = new THREE.Color( 0x000000 ); - this.emissive = new THREE.Color( 0x000000 ); - this.specular = new THREE.Color( 0xffffff ); - this.shininess = 30; - - this.wrapAround = false; - this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); - - this.map = null; - this.opacityMap = null; - - this.lightMap = null; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalScale = new THREE.Vector2( 1, 1 ); - - this.specularMap = null; - - this.envMap = null; - this.combine = THREE.MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.fog = true; - - this.shading = THREE.SmoothShading; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.vertexColors = THREE.NoColors; - - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; - - this.setValues( parameters ); - -}; - -THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.MeshPhongMaterial.prototype.clone = function () { - - var material = new THREE.MeshPhongMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - material.ambient.copy( this.ambient ); - material.emissive.copy( this.emissive ); - material.specular.copy( this.specular ); - material.shininess = this.shininess; - - material.wrapAround = this.wrapAround; - material.wrapRGB.copy( this.wrapRGB ); - - material.map = this.map; - material.opacityMap = this.opacityMap; - - material.lightMap = this.lightMap; - material.emissiveMap = this.emissiveMap; - - material.bumpMap = this.bumpMap; - material.bumpScale = this.bumpScale; - - material.normalMap = this.normalMap; - material.normalScale.copy( this.normalScale ); - - material.specularMap = this.specularMap; - - material.envMap = this.envMap; - material.combine = this.combine; - material.reflectivity = this.reflectivity; - material.refractionRatio = this.refractionRatio; - - material.fog = this.fog; - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; - - return material; - -}; - -/** - * - * @author bhouston / http://clara.io/ - * - */ - -THREE.MeshPhysicalMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); // diffuse - this.map = null; - this.opacityMap = null; - this.fog = true; - - this.falloff = false; - this.falloffColor = new THREE.Color( 0xffffff ); - this.falloffMap = null; - this.falloffBlendParams = new THREE.Vector4( 1.0, 0.0, 0.0, 1.0 ); - - this.specular = new THREE.Color( 0xffffff ); - this.specularMap = null; - - this.roughness = 0.5; - this.roughnessMap = null; - - this.metallic = 0.0; - this.metallicMap = null; - - this.clearCoat = 0.0; // 0 means no clear coat, 1 means complete clear coat. - this.clearCoatRoughness = 0.2; - - this.anisotropy = 0.0; // valid range is [-1,1].-1 is max vertical elongation, 0 is normal, +1 is max horizontal elongation - this.anisotropyMap = null; // only R is read and considered to be anisotropy. To get negative values, use texture brightness, gain - this.anisotropyRotation = 0.0; // converted to radias via multiplication by 2*PI. Thus the range [ 0 - 1 ] maps to radian [0, PI]. - this.anisotropyRotationMap = null; // only R is read and considered to be anisotropyRotation. - - this.translucency = new THREE.Color( 0x000000 ); - this.translucencyMap = null; - this.translucencyNormalAlpha = 0.75; - this.translucencyNormalPower = 1.0; - this.translucencyViewPower = 2.0; - this.translucencyViewAlpha = 0.75; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalScale = new THREE.Vector2( 1, 1 ); - - this.emissive = new THREE.Color( 0x000000 ); - this.emissiveMap = null; // given off arbitrarily by the object in all directions. Basically GI. - - this.ambient = new THREE.Color( 0x000000 ); - this.lightMap = null; // incoming light - - this.envMap = null; // Incoming environmental light. - this.diffuseEnvMap = null; // irradiance light. - - this.combine = THREE.AddOperation; - - this.shading = THREE.SmoothShading - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.blending = THREE.CustomBlending; - this.blendSrc = THREE.OneFactor; // output of shader must be premultiplied - this.blendDst = THREE.OneMinusSrcAlphaFactor; - this.blendEquation = THREE.AddEquation; - - this.vertexColors = THREE.NoColors; - - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; - - this.setValues( parameters ); -}; - -THREE.MeshPhysicalMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.MeshPhysicalMaterial.prototype.clone = function () { - - var material = new THREE.MeshPhysicalMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - material.map = this.map; - material.opacityMap = this.opacityMap; - material.fog = this.fog; - - material.falloff = this.falloff; - material.falloffColor.copy( this.falloffColor ); - material.falloffMap = this.falloffMap; - material.falloffBlendParams.copy( this.falloffBlendParams ); - - material.specular.copy( this.specular ); - material.specularMap = this.specularMap; - - material.roughness = this.roughness; - material.roughnessMap = this.roughnessMap; - material.metallic = this.metallic; - material.metallicMap = this.metallicMap; - - material.shading = this.shading; - - material.translucency.copy( this.translucency ); - material.translucencyMap = this.translucencyMap; - material.translucencyNormalAlpha = this.translucencyNormalAlpha; - material.translucencyNormalPower = this.translucencyNormalPower; - material.translucencyViewPower = this.translucencyViewPower; - material.translucencyViewAlpha = this.translucencyViewAlpha; - - material.bumpMap = this.bumpMap; - material.bumpScale = this.bumpScale; - - material.normalMap = this.normalMap; - material.normalScale.copy( this.normalScale ); - - material.emissive.copy( this.emissive ); - material.emissiveMap = this.emissiveMap; - - material.ambient.copy( this.ambient ); - material.lightMap = this.lightMap; - - material.envMap = this.envMap; - material.diffuseEnvMap = this.diffuseEnvMap; - - material.combine = this.combine; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - material.wireframeLinecap = this.wireframeLinecap; - material.wireframeLinejoin = this.wireframeLinejoin; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * opacity: , - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: - * } - */ - -THREE.MeshDepthMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.setValues( parameters ); - -}; - -THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.MeshDepthMaterial.prototype.clone = function () { - - var material = new THREE.MeshDepthMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * - * parameters = { - * opacity: , - * - * shading: THREE.FlatShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: - * } - */ - -THREE.MeshNormalMaterial = function ( parameters ) { - - THREE.Material.call( this, parameters ); - - this.shading = THREE.FlatShading; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.morphTargets = false; - - this.setValues( parameters ); - -}; - -THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.MeshNormalMaterial.prototype.clone = function () { - - var material = new THREE.MeshNormalMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.MeshFaceMaterial = function ( materials ) { - - this.materials = materials instanceof Array ? materials : []; - -}; - -THREE.MeshFaceMaterial.prototype.clone = function () { - - var material = new THREE.MeshFaceMaterial(); - - for ( var i = 0; i < this.materials.length; i ++ ) { - - material.materials.push( this.materials[ i ].clone() ); - - } - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * size: , - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * vertexColors: , - * - * fog: - * } - */ - -THREE.ParticleSystemMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); - - this.map = null; - - this.size = 1; - this.sizeAttenuation = true; - - this.vertexColors = false; - - this.fog = true; - - this.setValues( parameters ); - -}; - -THREE.ParticleSystemMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.ParticleSystemMaterial.prototype.clone = function () { - - var material = new THREE.ParticleSystemMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - - material.map = this.map; - - material.size = this.size; - material.sizeAttenuation = this.sizeAttenuation; - - material.vertexColors = this.vertexColors; - - material.fog = this.fog; - - return material; - -}; - -// backwards compatibility - -THREE.ParticleBasicMaterial = THREE.ParticleSystemMaterial; - -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * fragmentShader: , - * vertexShader: , - * - * uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } }, - * - * defines: { "label" : "value" }, - * - * shading: THREE.SmoothShading, - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * - * lights: , - * - * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, - * - * skinning: , - * morphTargets: , - * morphNormals: , - * - * fog: - * } - */ - -THREE.ShaderMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.shaderID = null; - this.fragmentShader = "void main() {}"; - this.vertexShader = "void main() {}"; - this.uniforms = {}; - this.defines = {}; - this.attributes = null; - - this.shading = THREE.SmoothShading; - - this.linewidth = 1; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.fog = false; // set to use scene fog - - this.lights = false; // set to use scene lights - - this.vertexColors = THREE.NoColors; // set to use "color" attribute stream - - this.skinning = false; // set to use skinning attribute streams - - this.morphTargets = false; // set to use morph targets - this.morphNormals = false; // set to use morph normals - - // When rendered geometry doesn't include these attributes but the material does, - // use these default values in WebGL. This avoids errors when buffer data is missing. - this.defaultAttributeValues = { - "color" : [ 1, 1, 1], - "uv" : [ 0, 0 ], - "uv2" : [ 0, 0 ] - }; - - // By default, bind position to attribute index 0. In WebGL, attribute 0 - // should always be used to avoid potentially expensive emulation. - this.index0AttributeName = "position"; - - this.setValues( parameters ); - -}; - -THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.ShaderMaterial.prototype.clone = function () { - - var material = new THREE.ShaderMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.fragmentShader = this.fragmentShader; - material.vertexShader = this.vertexShader; - - material.uniforms = THREE.UniformsUtils.clone( this.uniforms ); - - material.attributes = this.attributes; - material.defines = this.defines; - - material.shading = this.shading; - - material.wireframe = this.wireframe; - material.wireframeLinewidth = this.wireframeLinewidth; - - material.fog = this.fog; - - material.lights = this.lights; - - material.vertexColors = this.vertexColors; - - material.skinning = this.skinning; - - material.morphTargets = this.morphTargets; - material.morphNormals = this.morphNormals; - - return material; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * blending: THREE.NormalBlending, - * depthTest: , - * depthWrite: , - * - * uvOffset: new THREE.Vector2(), - * uvScale: new THREE.Vector2(), - * - * fog: - * } - */ - -THREE.SpriteMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - // defaults - - this.color = new THREE.Color( 0xffffff ); - this.map = null; - - this.rotation = 0; - - this.fog = false; - - // set parameters - - this.setValues( parameters ); - -}; - -THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.SpriteMaterial.prototype.clone = function () { - - var material = new THREE.SpriteMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - material.map = this.map; - - material.rotation = this.rotation; - - material.fog = this.fog; - - return material; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * - * parameters = { - * color: , - * program: , - * opacity: , - * blending: THREE.NormalBlending - * } - */ - -THREE.SpriteCanvasMaterial = function ( parameters ) { - - THREE.Material.call( this ); - - this.color = new THREE.Color( 0xffffff ); - this.program = function ( context, color ) {}; - - this.setValues( parameters ); - -}; - -THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype ); - -THREE.SpriteCanvasMaterial.prototype.clone = function () { - - var material = new THREE.SpriteCanvasMaterial(); - - THREE.Material.prototype.clone.call( this, material ); - - material.color.copy( this.color ); - material.program = this.program; - - return material; - -}; - -// backwards compatibility - -THREE.ParticleCanvasMaterial = THREE.SpriteCanvasMaterial; -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author szimek / https://github.com/szimek/ - * @author bhouston / https://clara.io/ - */ - -THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - - this.id = THREE.TextureIdCount ++; - this.uuid = THREE.Math.generateUUID(); - - this.name = ''; - - this.image = image; - this.mipmaps = []; - - this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping(); - - this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; - this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; - - this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; - this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; - - this.anisotropy = anisotropy !== undefined ? anisotropy : 1; - - this.format = format !== undefined ? format : THREE.RGBAFormat; - this.type = type !== undefined ? type : THREE.UnsignedByteType; - - this.offset = new THREE.Vector2( 0, 0 ); - this.repeat = new THREE.Vector2( 1, 1 ); - - // formula used - // x' = ( x - gainPivot ) * gain + brightness + gainPivot - // for standard contrast adjust, set gain to contrast, and gainPivot to 0.5 - this.invert = false; - this.gainPivot = 0.0; - this.gain = 1.0; - this.brightness = 0.0; - this.encoding = THREE.sRGB; - - this.generateMipmaps = true; - this.premultiplyAlpha = false; - this.flipY = true; - this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) - - this._needsUpdate = false; - this.onUpdate = null; - -}; - -THREE.Texture.prototype = { - - constructor: THREE.Texture, - - get needsUpdate () { - - return this._needsUpdate; - - }, - - set needsUpdate ( value ) { - - if ( value === true ) this.update(); - - this._needsUpdate = value; - - }, - - clone: function ( texture ) { - - if ( texture === undefined ) texture = new THREE.Texture(); - - texture.image = this.image; - texture.mipmaps = this.mipmaps.slice(0); - - texture.mapping = this.mapping; - - texture.wrapS = this.wrapS; - texture.wrapT = this.wrapT; - - texture.magFilter = this.magFilter; - texture.minFilter = this.minFilter; - - texture.anisotropy = this.anisotropy; - - texture.format = this.format; - texture.type = this.type; - - texture.offset.copy( this.offset ); - texture.repeat.copy( this.repeat ); - - texture.invert = this.invert; - texture.gainPivot = this.gainPivot; - texture.gain = this.gain; - texture.brightness = this.brightness; - texture.encoding = this.encoding; - - texture.generateMipmaps = this.generateMipmaps; - texture.premultiplyAlpha = this.premultiplyAlpha; - texture.flipY = this.flipY; - texture.unpackAlignment = this.unpackAlignment; - - return texture; - - }, - - update: function () { - - this.dispatchEvent( { type: 'update' } ); - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype ); - -THREE.TextureIdCount = 0; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { - - THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.image = { width: width, height: height }; - this.mipmaps = mipmaps; - - this.generateMipmaps = false; // WebGL currently can't generate mipmaps for compressed textures, they must be embedded in DDS file - -}; - -THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype ); - -THREE.CompressedTexture.prototype.clone = function () { - - var texture = new THREE.CompressedTexture(); - - THREE.Texture.prototype.clone.call( this, texture ); - - return texture; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { - - THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.image = { data: data, width: width, height: height }; - -}; - -THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype ); - -THREE.DataTexture.prototype.clone = function () { - - var texture = new THREE.DataTexture(); - - THREE.Texture.prototype.clone.call( this, texture ); - - return texture; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.ParticleSystem = function ( geometry, material ) { - - THREE.Object3D.call( this ); - - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.ParticleSystemMaterial( { color: Math.random() * 0xffffff } ); - - this.sortParticles = false; - this.frustumCulled = false; - -}; - -THREE.ParticleSystem.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.ParticleSystem.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.ParticleSystem( this.geometry, this.material ); - - object.sortParticles = this.sortParticles; - - THREE.Object3D.prototype.clone.call( this, object ); - - return object; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Line = function ( geometry, material, type ) { - - THREE.Object3D.call( this ); - - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); - - this.type = ( type !== undefined ) ? type : THREE.LineStrip; - -}; - -THREE.LineStrip = 0; -THREE.LinePieces = 1; - -THREE.Line.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.Line.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.type ); - - THREE.Object3D.prototype.clone.call( this, object ); - - return object; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author jonobr1 / http://jonobr1.com/ - */ - -THREE.Mesh = function ( geometry, material ) { - - THREE.Object3D.call( this ); - - this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); - this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ); - - this.updateMorphTargets(); - -}; - -THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.Mesh.prototype.updateMorphTargets = function () { - - if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) { - - this.morphTargetBase = -1; - this.morphTargetForcedOrder = []; - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) { - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; - - } - - } - -}; - -THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { - - if ( this.morphTargetDictionary[ name ] !== undefined ) { - - return this.morphTargetDictionary[ name ]; - - } - - THREE.onwarning( "THREE.Mesh.getMorphTargetIndexByName: morph target " + name + " does not exist. Returning 0." ); - - return 0; - -}; - -THREE.Mesh.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material ); - - THREE.Object3D.prototype.clone.call( this, object ); - - return object; - -}; - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Bone = function( belongsToSkin ) { - - THREE.Object3D.call( this ); - - this.skin = belongsToSkin; - this.skinMatrix = new THREE.Matrix4(); - -}; - -THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.Bone.prototype.update = function ( parentSkinMatrix, forceUpdate ) { - - // update local - - if ( this.matrixAutoUpdate ) { - - forceUpdate |= this.updateMatrix(); - - } - - // update skin matrix - - if ( forceUpdate || this.matrixWorldNeedsUpdate ) { - - if( parentSkinMatrix ) { - - this.skinMatrix.multiplyMatrices( parentSkinMatrix, this.matrix ); - - } else { - - this.skinMatrix.copy( this.matrix ); - - } - - this.matrixWorldNeedsUpdate = false; - forceUpdate = true; - - } - - // update children - - var child, i, l = this.children.length; - - for ( i = 0; i < l; i ++ ) { - - this.children[ i ].update( this.skinMatrix, forceUpdate ); - - } - -}; - - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { - - THREE.Mesh.call( this, geometry, material ); - - // - - this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; - - // init bones - - this.identityMatrix = new THREE.Matrix4(); - - this.bones = []; - this.boneMatrices = []; - - var b, bone, gbone, p, q, s; - - if ( this.geometry && this.geometry.bones !== undefined ) { - - for ( b = 0; b < this.geometry.bones.length; b ++ ) { - - gbone = this.geometry.bones[ b ]; - - p = gbone.pos; - q = gbone.rotq; - s = gbone.scl; - - bone = this.addBone(); - - bone.name = gbone.name; - bone.position.set( p[0], p[1], p[2] ); - bone.quaternion.set( q[0], q[1], q[2], q[3] ); - - if ( s !== undefined ) { - - bone.scale.set( s[0], s[1], s[2] ); - - } else { - - bone.scale.set( 1, 1, 1 ); - - } - - } - - for ( b = 0; b < this.bones.length; b ++ ) { - - gbone = this.geometry.bones[ b ]; - bone = this.bones[ b ]; - - if ( gbone.parent === -1 ) { - - this.add( bone ); - - } else { - - this.bones[ gbone.parent ].add( bone ); - - } - - } - - // - - var nBones = this.bones.length; - - if ( this.useVertexTexture ) { - - // layout (1 matrix = 4 pixels) - // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) - // with 8x8 pixel texture max 16 bones (8 * 8 / 4) - // 16x16 pixel texture max 64 bones (16 * 16 / 4) - // 32x32 pixel texture max 256 bones (32 * 32 / 4) - // 64x64 pixel texture max 1024 bones (64 * 64 / 4) - - var size; - - if ( nBones > 256 ) - size = 64; - else if ( nBones > 64 ) - size = 32; - else if ( nBones > 16 ) - size = 16; - else - size = 8; - - this.boneTextureWidth = size; - this.boneTextureHeight = size; - - this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel - this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType ); - this.boneTexture.minFilter = THREE.NearestFilter; - this.boneTexture.magFilter = THREE.NearestFilter; - this.boneTexture.generateMipmaps = false; - this.boneTexture.flipY = false; - - } else { - - this.boneMatrices = new Float32Array( 16 * nBones ); - - } - - this.pose(); - - } - -}; - -THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype ); - -THREE.SkinnedMesh.prototype.addBone = function( bone ) { - - if ( bone === undefined ) { - - bone = new THREE.Bone( this ); - - } - - this.bones.push( bone ); - - return bone; - -}; - -THREE.SkinnedMesh.prototype.updateMatrixWorld = function () { - - var offsetMatrix = new THREE.Matrix4(); - - return function ( force ) { - - this.matrixAutoUpdate && this.updateMatrix(); - - // update matrixWorld - - if ( this.matrixWorldNeedsUpdate || force ) { - - if ( this.parent ) { - - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - - } else { - - this.matrixWorld.copy( this.matrix ); - - } - - this.matrixWorldNeedsUpdate = false; - - force = true; - - } - - // update children - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - var child = this.children[ i ]; - - if ( child instanceof THREE.Bone ) { - - child.update( this.identityMatrix, false ); - - } else { - - child.updateMatrixWorld( true ); - - } - - } - - // make a snapshot of the bones' rest position - - if ( this.boneInverses == undefined ) { - - this.boneInverses = []; - - for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - - var inverse = new THREE.Matrix4(); - - inverse.getInverse( this.bones[ b ].skinMatrix ); - - this.boneInverses.push( inverse ); - - } - - } - - // flatten bone matrices to array - - for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { - - // compute the offset between the current and the original transform; - - // TODO: we could get rid of this multiplication step if the skinMatrix - // was already representing the offset; however, this requires some - // major changes to the animation system - - offsetMatrix.multiplyMatrices( this.bones[ b ].skinMatrix, this.boneInverses[ b ] ); - offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 ); - - } - - if ( this.useVertexTexture ) { - - this.boneTexture.needsUpdate = true; - - } - - }; - -}(); - -THREE.SkinnedMesh.prototype.pose = function () { - - this.updateMatrixWorld( true ); - - this.normalizeSkinWeights(); - -}; - -THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () { - - if ( this.geometry instanceof THREE.Geometry ) { - - for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) { - - var sw = this.geometry.skinWeights[ i ]; - - var scale = 1.0 / sw.lengthManhattan(); - - if ( scale !== Infinity ) { - - sw.multiplyScalar( scale ); - - } else { - - sw.set( 1 ); // this will be normalized by the shader anyway - - } - - } - - } else { - - // skinning weights assumed to be normalized for THREE.BufferGeometry - - } - -}; - -THREE.SkinnedMesh.prototype.clone = function ( object ) { - - if ( object === undefined ) { - - object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture ); - - } - - THREE.Mesh.prototype.clone.call( this, object ); - - return object; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.MorphAnimMesh = function ( geometry, material ) { - - THREE.Mesh.call( this, geometry, material ); - - // API - - this.duration = 1000; // milliseconds - this.mirroredLoop = false; - this.time = 0; - - // internals - - this.lastKeyframe = 0; - this.currentKeyframe = 0; - - this.direction = 1; - this.directionBackwards = false; - - this.setFrameRange( 0, this.geometry.morphTargets.length - 1 ); - -}; - -THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype ); - -THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) { - - this.startKeyframe = start; - this.endKeyframe = end; - - this.length = this.endKeyframe - this.startKeyframe + 1; - -}; - -THREE.MorphAnimMesh.prototype.setDirectionForward = function () { - - this.direction = 1; - this.directionBackwards = false; - -}; - -THREE.MorphAnimMesh.prototype.setDirectionBackward = function () { - - this.direction = -1; - this.directionBackwards = true; - -}; - -THREE.MorphAnimMesh.prototype.parseAnimations = function () { - - var geometry = this.geometry; - - if ( ! geometry.animations ) geometry.animations = {}; - - var firstAnimation, animations = geometry.animations; - - var pattern = /([a-z]+)(\d+)/; - - for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { - - var morph = geometry.morphTargets[ i ]; - var parts = morph.name.match( pattern ); - - if ( parts && parts.length > 1 ) { - - var label = parts[ 1 ]; - var num = parts[ 2 ]; - - if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: -Infinity }; - - var animation = animations[ label ]; - - if ( i < animation.start ) animation.start = i; - if ( i > animation.end ) animation.end = i; - - if ( ! firstAnimation ) firstAnimation = label; - - } - - } - - geometry.firstAnimation = firstAnimation; - -}; - -THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) { - - if ( ! this.geometry.animations ) this.geometry.animations = {}; - - this.geometry.animations[ label ] = { start: start, end: end }; - -}; - -THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) { - - var animation = this.geometry.animations[ label ]; - - if ( animation ) { - - this.setFrameRange( animation.start, animation.end ); - this.duration = 1000 * ( ( animation.end - animation.start ) / fps ); - this.time = 0; - - } else { - - THREE.onwarning( "animation[" + label + "] undefined" ); - - } - -}; - -THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) { - - var frameTime = this.duration / this.length; - - this.time += this.direction * delta; - - if ( this.mirroredLoop ) { - - if ( this.time > this.duration || this.time < 0 ) { - - this.direction *= -1; - - if ( this.time > this.duration ) { - - this.time = this.duration; - this.directionBackwards = true; - - } - - if ( this.time < 0 ) { - - this.time = 0; - this.directionBackwards = false; - - } - - } - - } else { - - this.time = this.time % this.duration; - - if ( this.time < 0 ) this.time += this.duration; - - } - - var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 ); - - if ( keyframe !== this.currentKeyframe ) { - - this.morphTargetInfluences[ this.lastKeyframe ] = 0; - this.morphTargetInfluences[ this.currentKeyframe ] = 1; - - this.morphTargetInfluences[ keyframe ] = 0; - - this.lastKeyframe = this.currentKeyframe; - this.currentKeyframe = keyframe; - - } - - var mix = ( this.time % frameTime ) / frameTime; - - if ( this.directionBackwards ) { - - mix = 1 - mix; - - } - - this.morphTargetInfluences[ this.currentKeyframe ] = mix; - this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix; - -}; - -THREE.MorphAnimMesh.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material ); - - object.duration = this.duration; - object.mirroredLoop = this.mirroredLoop; - object.time = this.time; - - object.lastKeyframe = this.lastKeyframe; - object.currentKeyframe = this.currentKeyframe; - - object.direction = this.direction; - object.directionBackwards = this.directionBackwards; - - THREE.Mesh.prototype.clone.call( this, object ); - - return object; - -}; - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.LOD = function () { - - THREE.Object3D.call( this ); - - this.objects = []; - -}; - - -THREE.LOD.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.LOD.prototype.addLevel = function ( object, distance ) { - - if ( distance === undefined ) distance = 0; - - distance = Math.abs( distance ); - - for ( var l = 0; l < this.objects.length; l ++ ) { - - if ( distance < this.objects[ l ].distance ) { - - break; - - } - - } - - this.objects.splice( l, 0, { distance: distance, object: object } ); - this.add( object ); - -}; - -THREE.LOD.prototype.getObjectForDistance = function ( distance ) { - - for ( var i = 1, l = this.objects.length; i < l; i ++ ) { - - if ( distance < this.objects[ i ].distance ) { - - break; - - } - - } - - return this.objects[ i - 1 ].object; - -}; - -THREE.LOD.prototype.update = function () { - - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - - return function ( camera ) { - - if ( this.objects.length > 1 ) { - - v1.setFromMatrixPosition( camera.matrixWorld ); - v2.setFromMatrixPosition( this.matrixWorld ); - - var distance = v1.distanceTo( v2 ); - - this.objects[ 0 ].object.visible = true; - - for ( var i = 1, l = this.objects.length; i < l; i ++ ) { - - if ( distance >= this.objects[ i ].distance ) { - - this.objects[ i - 1 ].object.visible = false; - this.objects[ i ].object.visible = true; - - } else { - - break; - - } - - } - - for( ; i < l; i ++ ) { - - this.objects[ i ].object.visible = false; - - } - - } - - }; - -}(); - -THREE.LOD.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.LOD(); - - THREE.Object3D.prototype.clone.call( this, object ); - - for ( var i = 0, l = this.objects.length; i < l; i ++ ) { - var x = this.objects[i].object.clone(); - x.visible = i === 0; - object.addLevel( x, this.objects[i].distance ); - } - - return object; - -}; - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Sprite = ( function () { - - var geometry = new THREE.Geometry2( 3 ); - geometry.vertices.set( [ - 0.5, - 0.5, 0, 0.5, - 0.5, 0, 0.5, 0.5, 0 ] ); - - return function ( material ) { - - THREE.Object3D.call( this ); - - this.geometry = geometry; - this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial(); - - }; - -} )(); - -THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype ); - -/* - * Custom update matrix - */ - -THREE.Sprite.prototype.updateMatrix = function () { - - this.matrix.compose( this.position, this.quaternion, this.scale ); - - this.matrixWorldNeedsUpdate = true; - -}; - -THREE.Sprite.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.Sprite( this.material ); - - THREE.Object3D.prototype.clone.call( this, object ); - - return object; - -}; - -// Backwards compatibility - -THREE.Particle = THREE.Sprite; -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.Scene = function () { - - THREE.Object3D.call( this ); - - this.fog = null; - this.overrideMaterial = null; - - this.autoUpdate = true; // checked by the renderer - this.matrixAutoUpdate = false; - - this.__lights = []; - - this.__objectsAdded = []; - this.__objectsRemoved = []; - -}; - -THREE.Scene.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.Scene.prototype.__addObject = function ( object ) { - - if ( object instanceof THREE.Light ) { - - if ( this.__lights.indexOf( object ) === - 1 ) { - - this.__lights.push( object ); - - } - - if ( object.target && object.target.parent === undefined ) { - - this.add( object.target ); - - } - - } else if ( !( object instanceof THREE.Camera || object instanceof THREE.Bone ) ) { - - this.__objectsAdded.push( object ); - - // check if previously removed - - var i = this.__objectsRemoved.indexOf( object ); - - if ( i !== -1 ) { - - this.__objectsRemoved.splice( i, 1 ); - - } - - } - - this.dispatchEvent( { type: 'objectAdded', object: object } ); - object.dispatchEvent( { type: 'addedToScene', scene: this } ); - - for ( var c = 0; c < object.children.length; c ++ ) { - - this.__addObject( object.children[ c ] ); - - } - -}; - -THREE.Scene.prototype.__removeObject = function ( object ) { - - if ( object instanceof THREE.Light ) { - - var i = this.__lights.indexOf( object ); - - if ( i !== -1 ) { - - this.__lights.splice( i, 1 ); - - } - - if ( object.shadowCascadeArray ) { - - for ( var x = 0; x < object.shadowCascadeArray.length; x ++ ) { - - this.__removeObject( object.shadowCascadeArray[ x ] ); - - } - - } - - } else if ( !( object instanceof THREE.Camera ) ) { - - this.__objectsRemoved.push( object ); - - // check if previously added - - var i = this.__objectsAdded.indexOf( object ); - - if ( i !== -1 ) { - - this.__objectsAdded.splice( i, 1 ); - - } - - } - - this.dispatchEvent( { type: 'objectRemoved', object: object } ); - object.dispatchEvent( { type: 'removedFromScene', scene: this } ); - - for ( var c = 0; c < object.children.length; c ++ ) { - - this.__removeObject( object.children[ c ] ); - - } - -}; - -THREE.Scene.prototype.clone = function ( object ) { - - if ( object === undefined ) object = new THREE.Scene(); - - THREE.Object3D.prototype.clone.call(this, object); - - if ( this.fog !== null ) object.fog = this.fog.clone(); - if ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone(); - - object.autoUpdate = this.autoUpdate; - object.matrixAutoUpdate = this.matrixAutoUpdate; - - return object; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Fog = function ( color, near, far ) { - - this.name = ''; - - this.color = new THREE.Color( color ); - - this.near = ( near !== undefined ) ? near : 1; - this.far = ( far !== undefined ) ? far : 1000; - -}; - -THREE.Fog.prototype.clone = function () { - - return new THREE.Fog( this.color.getHex(), this.near, this.far ); - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.FogExp2 = function ( color, density ) { - - this.name = ''; - - this.color = new THREE.Color( color ); - this.density = ( density !== undefined ) ? density : 0.00025; - -}; - -THREE.FogExp2.prototype.clone = function () { - - return new THREE.FogExp2( this.color.getHex(), this.density ); - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.CanvasRenderer = function ( parameters ) { - - console.log( 'THREE.CanvasRenderer', THREE.REVISION ); - - var smoothstep = THREE.Math.smoothstep; - - parameters = parameters || {}; - - var _this = this, - _renderData, _elements, _lights, - _projector = new THREE.Projector(), - - _canvas = parameters.canvas !== undefined - ? parameters.canvas - : document.createElement( 'canvas' ), - - _canvasWidth = _canvas.width, - _canvasHeight = _canvas.height, - _canvasWidthHalf = Math.floor( _canvasWidth / 2 ), - _canvasHeightHalf = Math.floor( _canvasHeight / 2 ), - - _context = _canvas.getContext( '2d', { - alpha: parameters.alpha === true - } ), - - _clearColor = new THREE.Color( 0x000000 ), - _clearAlpha = 0, - - _contextGlobalAlpha = 1, - _contextGlobalCompositeOperation = 0, - _contextStrokeStyle = null, - _contextFillStyle = null, - _contextLineWidth = null, - _contextLineCap = null, - _contextLineJoin = null, - _contextDashSize = null, - _contextGapSize = 0, - - _camera, - - _v1, _v2, _v3, _v4, - _v5 = new THREE.RenderableVertex(), - _v6 = new THREE.RenderableVertex(), - - _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, - _v4x, _v4y, _v5x, _v5y, _v6x, _v6y, - - _color = new THREE.Color(), - _color1 = new THREE.Color(), - _color2 = new THREE.Color(), - _color3 = new THREE.Color(), - _color4 = new THREE.Color(), - - _diffuseColor = new THREE.Color(), - _emissiveColor = new THREE.Color(), - - _lightColor = new THREE.Color(), - - _patterns = {}, - - _near, _far, - - _image, _uvs, - _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, - - _clipBox = new THREE.Box2(), - _clearBox = new THREE.Box2(), - _elemBox = new THREE.Box2(), - - _ambientLight = new THREE.Color(), - _directionalLights = new THREE.Color(), - _pointLights = new THREE.Color(), - - _vector3 = new THREE.Vector3(), // Needed for PointLight - _normal = new THREE.Vector3(), - _normalViewMatrix = new THREE.Matrix3(), - - _pixelMap, _pixelMapContext, _pixelMapImage, _pixelMapData, - _gradientMap, _gradientMapContext, _gradientMapQuality = 16; - - _pixelMap = document.createElement( 'canvas' ); - _pixelMap.width = _pixelMap.height = 2; - - _pixelMapContext = _pixelMap.getContext( '2d' ); - _pixelMapContext.fillStyle = 'rgba(0,0,0,1)'; - _pixelMapContext.fillRect( 0, 0, 2, 2 ); - - _pixelMapImage = _pixelMapContext.getImageData( 0, 0, 2, 2 ); - _pixelMapData = _pixelMapImage.data; - - _gradientMap = document.createElement( 'canvas' ); - _gradientMap.width = _gradientMap.height = _gradientMapQuality; - - _gradientMapContext = _gradientMap.getContext( '2d' ); - _gradientMapContext.translate( - _gradientMapQuality / 2, - _gradientMapQuality / 2 ); - _gradientMapContext.scale( _gradientMapQuality, _gradientMapQuality ); - - _gradientMapQuality --; // Fix UVs - - // dash+gap fallbacks for Firefox and everything else - - if ( _context.setLineDash === undefined ) { - - if ( _context.mozDash !== undefined ) { - - _context.setLineDash = function ( values ) { - - _context.mozDash = values[ 0 ] !== null ? values : null; - - } - - } else { - - _context.setLineDash = function () {} - - } - - } - - this.domElement = _canvas; - - this.devicePixelRatio = parameters.devicePixelRatio !== undefined - ? parameters.devicePixelRatio - : self.devicePixelRatio !== undefined - ? self.devicePixelRatio - : 1; - - this.autoClear = true; - this.sortObjects = true; - this.sortElements = true; - - this.info = { - - render: { - - vertices: 0, - faces: 0 - - } - - } - - // WebGLRenderer compatibility - - this.supportsVertexTextures = function () {}; - this.setFaceCulling = function () {}; - - this.setSize = function ( width, height, updateStyle ) { - - _canvasWidth = width * this.devicePixelRatio; - _canvasHeight = height * this.devicePixelRatio; - - _canvasWidthHalf = Math.floor( _canvasWidth / 2 ); - _canvasHeightHalf = Math.floor( _canvasHeight / 2 ); - - _canvas.width = _canvasWidth; - _canvas.height = _canvasHeight; - - if ( this.devicePixelRatio !== 1 && updateStyle !== false ) { - - _canvas.style.width = width + 'px'; - _canvas.style.height = height + 'px'; - - } - - _clipBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ), - _clipBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); - - _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); - _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); - - _contextGlobalAlpha = 1; - _contextGlobalCompositeOperation = 0; - _contextStrokeStyle = null; - _contextFillStyle = null; - _contextLineWidth = null; - _contextLineCap = null; - _contextLineJoin = null; - - }; - - this.setClearColor = function ( color, alpha ) { - - _clearColor.set( color ); - _clearAlpha = alpha !== undefined ? alpha : 1; - - _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); - _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); - - }; - - this.setClearColorHex = function ( hex, alpha ) { - - THREE.onwarning( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); - this.setClearColor( hex, alpha ); - - }; - - this.getMaxAnisotropy = function () { - - return 0; - - }; - - this.clear = function () { - - _context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf ); - - if ( _clearBox.empty() === false ) { - - _clearBox.intersect( _clipBox ); - _clearBox.expandByScalar( 2 ); - - if ( _clearAlpha < 1 ) { - - _context.clearRect( - _clearBox.min.x | 0, - _clearBox.min.y | 0, - ( _clearBox.max.x - _clearBox.min.x ) | 0, - ( _clearBox.max.y - _clearBox.min.y ) | 0 - ); - - } - - if ( _clearAlpha > 0 ) { - - setBlending( THREE.NormalBlending ); - setOpacity( 1 ); - - setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' ); - - _context.fillRect( - _clearBox.min.x | 0, - _clearBox.min.y | 0, - ( _clearBox.max.x - _clearBox.min.x ) | 0, - ( _clearBox.max.y - _clearBox.min.y ) | 0 - ); - - } - - _clearBox.makeEmpty(); - - } - - }; - - // compatibility - - this.clearColor = function () {}; - this.clearDepth = function () {}; - this.clearStencil = function () {}; - - this.render = function ( scene, camera ) { - - if ( camera instanceof THREE.Camera === false ) { - - THREE.onerror( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' ); - return; - - } - - if ( this.autoClear === true ) this.clear(); - - _context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf ); - - _this.info.render.vertices = 0; - _this.info.render.faces = 0; - - _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements ); - _elements = _renderData.elements; - _lights = _renderData.lights; - _camera = camera; - - _normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse ); - - /* DEBUG - setFillStyle( 'rgba( 0, 255, 255, 0.5 )' ); - _context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y ); - */ - - calculateLights(); - - for ( var e = 0, el = _elements.length; e < el; e ++ ) { - - var element = _elements[ e ]; - - var material = element.material; - - if ( material === undefined || material.visible === false ) continue; - - _elemBox.makeEmpty(); - - if ( element instanceof THREE.RenderableSprite ) { - - _v1 = element; - _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf; - - renderSprite( _v1, element, material ); - - } else if ( element instanceof THREE.RenderableLine ) { - - _v1 = element.v1; _v2 = element.v2; - - _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; - _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; - - _elemBox.setFromPoints( [ - _v1.positionScreen, - _v2.positionScreen - ] ); - - if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { - - renderLine( _v1, _v2, element, material ); - - } - - } else if ( element instanceof THREE.RenderableFace ) { - - _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; - - if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue; - if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue; - if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue; - - _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; - _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; - _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf; - - if ( material.overdraw > 0 ) { - - expand( _v1.positionScreen, _v2.positionScreen, material.overdraw ); - expand( _v2.positionScreen, _v3.positionScreen, material.overdraw ); - expand( _v3.positionScreen, _v1.positionScreen, material.overdraw ); - - } - - _elemBox.setFromPoints( [ - _v1.positionScreen, - _v2.positionScreen, - _v3.positionScreen - ] ); - - if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { - - renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material ); - - } - - } - - /* DEBUG - setLineWidth( 1 ); - setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' ); - _context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y ); - */ - - _clearBox.union( _elemBox ); - - } - - /* DEBUG - setLineWidth( 1 ); - setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' ); - _context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y ); - */ - - _context.setTransform( 1, 0, 0, 1, 0, 0 ); - - }; - - // - - function calculateLights() { - - _ambientLight.setRGB( 0, 0, 0 ); - _directionalLights.setRGB( 0, 0, 0 ); - _pointLights.setRGB( 0, 0, 0 ); - - for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { - - var light = _lights[ l ]; - var lightColor = light.color; - - if ( light instanceof THREE.AmbientLight ) { - - _ambientLight.add( lightColor ); - - } else if ( light instanceof THREE.DirectionalLight ) { - - // for sprites - - _directionalLights.add( lightColor ); - - } else if ( light instanceof THREE.PointLight ) { - - // for sprites - - _pointLights.add( lightColor ); - - } - - } - - } - - function calculateLight( position, normal, color ) { - - for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { - - var light = _lights[ l ]; - - _lightColor.copy( light.color ); - - if ( light instanceof THREE.DirectionalLight ) { - - var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize(); - - var amount = normal.dot( lightPosition ); - - if ( amount <= 0 ) continue; - - amount *= light.intensity; - - color.add( _lightColor.multiplyScalar( amount ) ); - - } else if ( light instanceof THREE.PointLight ) { - - var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ); - - var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() ); - - if ( amount <= 0 ) continue; - - amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 ); - - if ( amount == 0 ) continue; - - amount *= light.intensity; - - color.add( _lightColor.multiplyScalar( amount ) ); - - } - - } - - } - - function renderSprite( v1, element, material ) { - - setOpacity( material.opacity ); - setBlending( material.blending ); - - var scaleX = element.scale.x * _canvasWidthHalf; - var scaleY = element.scale.y * _canvasHeightHalf; - - var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite - _elemBox.min.set( v1.x - dist, v1.y - dist ); - _elemBox.max.set( v1.x + dist, v1.y + dist ); - - if ( material instanceof THREE.SpriteMaterial || - material instanceof THREE.ParticleSystemMaterial ) { // Backwards compatibility - - var texture = material.map; - - if ( texture !== null ) { - - if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { - - if ( texture.image !== undefined && texture.image.width > 0 ) { - - textureToPattern( texture ); - - } - - texture.addEventListener( 'update', onTextureUpdate ); - - } - - var pattern = _patterns[ texture.id ]; - - if ( pattern !== undefined ) { - - setFillStyle( pattern ); - - } else { - - setFillStyle( 'rgba( 0, 0, 0, 1 )' ); - - } - - // - - var bitmap = texture.image; - - var ox = bitmap.width * texture.offset.x; - var oy = bitmap.height * texture.offset.y; - - var sx = bitmap.width * texture.repeat.x; - var sy = bitmap.height * texture.repeat.y; - - var cx = scaleX / sx; - var cy = scaleY / sy; - - _context.save(); - _context.translate( v1.x, v1.y ); - if ( material.rotation !== 0 ) _context.rotate( material.rotation ); - _context.translate( - scaleX / 2, - scaleY / 2 ); - _context.scale( cx, cy ); - _context.translate( - ox, - oy ); - _context.fillRect( ox, oy, sx, sy ); - _context.restore(); - - } else { // no texture - - setFillStyle( material.color.getStyle() ); - - _context.save(); - _context.translate( v1.x, v1.y ); - if ( material.rotation !== 0 ) _context.rotate( material.rotation ); - _context.scale( scaleX, - scaleY ); - _context.fillRect( - 0.5, - 0.5, 1, 1 ); - _context.restore(); - - } - - } else if ( material instanceof THREE.SpriteCanvasMaterial ) { - - setStrokeStyle( material.color.getStyle() ); - setFillStyle( material.color.getStyle() ); - - _context.save(); - _context.translate( v1.x, v1.y ); - if ( material.rotation !== 0 ) _context.rotate( material.rotation ); - _context.scale( scaleX, scaleY ); - - material.program( _context ); - - _context.restore(); - - } - - /* DEBUG - setStrokeStyle( 'rgb(255,255,0)' ); - _context.beginPath(); - _context.moveTo( v1.x - 10, v1.y ); - _context.lineTo( v1.x + 10, v1.y ); - _context.moveTo( v1.x, v1.y - 10 ); - _context.lineTo( v1.x, v1.y + 10 ); - _context.stroke(); - */ - - } - - function renderLine( v1, v2, element, material ) { - - setOpacity( material.opacity ); - setBlending( material.blending ); - - _context.beginPath(); - _context.moveTo( v1.positionScreen.x, v1.positionScreen.y ); - _context.lineTo( v2.positionScreen.x, v2.positionScreen.y ); - - if ( material instanceof THREE.LineBasicMaterial ) { - - setLineWidth( material.linewidth ); - setLineCap( material.linecap ); - setLineJoin( material.linejoin ); - - if ( material.vertexColors !== THREE.VertexColors ) { - - setStrokeStyle( material.color.getStyle() ); - - } else { - - var colorStyle1 = element.vertexColors[0].getStyle(); - var colorStyle2 = element.vertexColors[1].getStyle(); - - if ( colorStyle1 === colorStyle2 ) { - - setStrokeStyle( colorStyle1 ); - - } else { - - try { - - var grad = _context.createLinearGradient( - v1.positionScreen.x, - v1.positionScreen.y, - v2.positionScreen.x, - v2.positionScreen.y - ); - grad.addColorStop( 0, colorStyle1 ); - grad.addColorStop( 1, colorStyle2 ); - - } catch ( exception ) { - - grad = colorStyle1; - - } - - setStrokeStyle( grad ); - - } - - } - - _context.stroke(); - _elemBox.expandByScalar( material.linewidth * 2 ); - - } else if ( material instanceof THREE.LineDashedMaterial ) { - - setLineWidth( material.linewidth ); - setLineCap( material.linecap ); - setLineJoin( material.linejoin ); - setStrokeStyle( material.color.getStyle() ); - setDashAndGap( material.dashSize, material.gapSize ); - - _context.stroke(); - - _elemBox.expandByScalar( material.linewidth * 2 ); - - setDashAndGap( null, null ); - - } - - } - - function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) { - - _this.info.render.vertices += 3; - _this.info.render.faces ++; - - setOpacity( material.opacity ); - setBlending( material.blending ); - - _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y; - _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y; - _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y; - - drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y ); - - if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial || material instanceof THREE.MeshPhysicalMaterial ) && material.map === null ) { - - _diffuseColor.copy( material.color ); - _emissiveColor.copy( material.emissive ); - - if ( material.vertexColors === THREE.FaceColors ) { - - _diffuseColor.multiply( element.color ); - - } - - if ( material.wireframe === false && material.shading === THREE.SmoothShading && element.vertexNormalsLength === 3 ) { - - _color1.copy( _ambientLight ); - _color2.copy( _ambientLight ); - _color3.copy( _ambientLight ); - - calculateLight( element.v1.positionWorld, element.vertexNormalsModel[ 0 ], _color1 ); - calculateLight( element.v2.positionWorld, element.vertexNormalsModel[ 1 ], _color2 ); - calculateLight( element.v3.positionWorld, element.vertexNormalsModel[ 2 ], _color3 ); - - _color1.multiply( _diffuseColor ).add( _emissiveColor ); - _color2.multiply( _diffuseColor ).add( _emissiveColor ); - _color3.multiply( _diffuseColor ).add( _emissiveColor ); - _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); - - _image = getGradientTexture( _color1, _color2, _color3, _color4 ); - - clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); - - } else { - - _color.copy( _ambientLight ); - - calculateLight( element.centroidModel, element.normalModel, _color ); - - _color.multiply( _diffuseColor ).add( _emissiveColor ); - - material.wireframe === true - ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) - : fillPath( _color ); - - } - - } else if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) { - - if ( material.map !== null ) { - - if ( material.map.mapping instanceof THREE.UVMapping ) { - - _uvs = element.uvs[ 0 ]; - patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map ); - - } - - - } else if ( material.envMap !== null ) { - - if ( material.envMap.mapping instanceof THREE.SphericalReflectionMapping ) { - - _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); - _uv1x = 0.5 * _normal.x + 0.5; - _uv1y = 0.5 * _normal.y + 0.5; - - _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); - _uv2x = 0.5 * _normal.x + 0.5; - _uv2y = 0.5 * _normal.y + 0.5; - - _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); - _uv3x = 0.5 * _normal.x + 0.5; - _uv3y = 0.5 * _normal.y + 0.5; - - patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap ); - - }/* else if ( material.envMap.mapping === THREE.SphericalRefractionMapping ) { - - - - }*/ - - - } else { - - _color.copy( material.color ); - - if ( material.vertexColors === THREE.FaceColors ) { - - _color.multiply( element.color ); - - } - - material.wireframe === true - ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) - : fillPath( _color ); - - } - - } else if ( material instanceof THREE.MeshDepthMaterial ) { - - _near = _camera.near; - _far = _camera.far; - - _color1.r = _color1.g = _color1.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _near, _far ); - _color2.r = _color2.g = _color2.b = 1 - smoothstep( v2.positionScreen.z * v2.positionScreen.w, _near, _far ); - _color3.r = _color3.g = _color3.b = 1 - smoothstep( v3.positionScreen.z * v3.positionScreen.w, _near, _far ); - _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); - - _image = getGradientTexture( _color1, _color2, _color3, _color4 ); - - clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); - - } else if ( material instanceof THREE.MeshNormalMaterial ) { - - if ( material.shading === THREE.FlatShading ) { - - _normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix ); - - _color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); - - material.wireframe === true - ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) - : fillPath( _color ); - - } else if ( material.shading === THREE.SmoothShading ) { - - _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); - _color1.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); - - _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); - _color2.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); - - _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); - _color3.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); - - _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); - - _image = getGradientTexture( _color1, _color2, _color3, _color4 ); - - clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); - - } - - } - - } - - // - - function drawTriangle( x0, y0, x1, y1, x2, y2 ) { - - _context.beginPath(); - _context.moveTo( x0, y0 ); - _context.lineTo( x1, y1 ); - _context.lineTo( x2, y2 ); - _context.closePath(); - - } - - function strokePath( color, linewidth, linecap, linejoin ) { - - setLineWidth( linewidth ); - setLineCap( linecap ); - setLineJoin( linejoin ); - setStrokeStyle( color.getStyle() ); - - _context.stroke(); - - _elemBox.expandByScalar( linewidth * 2 ); - - } - - function fillPath( color ) { - - setFillStyle( color.getStyle() ); - _context.fill(); - - } - - function onTextureUpdate ( event ) { - - textureToPattern( event.target ); - - } - - function textureToPattern( texture ) { - - var repeatX = texture.wrapS === THREE.RepeatWrapping; - var repeatY = texture.wrapT === THREE.RepeatWrapping; - - var image = texture.image; - - var canvas = document.createElement( 'canvas' ); - canvas.width = image.width; - canvas.height = image.height; - - var context = canvas.getContext( '2d' ); - context.setTransform( 1, 0, 0, - 1, 0, image.height ); - context.drawImage( image, 0, 0 ); - - _patterns[ texture.id ] = _context.createPattern( - canvas, repeatX === true && repeatY === true - ? 'repeat' - : repeatX === true && repeatY === false - ? 'repeat-x' - : repeatX === false && repeatY === true - ? 'repeat-y' - : 'no-repeat' - ); - - } - - function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) { - - if ( texture instanceof THREE.DataTexture ) return; - - if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { - - if ( texture.image !== undefined && texture.image.width > 0 ) { - - textureToPattern( texture ); - - } - - texture.addEventListener( 'update', onTextureUpdate ); - - } - - var pattern = _patterns[ texture.id ]; - - if ( pattern !== undefined ) { - - setFillStyle( pattern ); - - } else { - - setFillStyle( 'rgba(0,0,0,1)' ); - _context.fill(); - - return; - - } - - // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 - - var a, b, c, d, e, f, det, idet, - offsetX = texture.offset.x / texture.repeat.x, - offsetY = texture.offset.y / texture.repeat.y, - width = texture.image.width * texture.repeat.x, - height = texture.image.height * texture.repeat.y; - - u0 = ( u0 + offsetX ) * width; - v0 = ( v0 + offsetY ) * height; - - u1 = ( u1 + offsetX ) * width; - v1 = ( v1 + offsetY ) * height; - - u2 = ( u2 + offsetX ) * width; - v2 = ( v2 + offsetY ) * height; - - x1 -= x0; y1 -= y0; - x2 -= x0; y2 -= y0; - - u1 -= u0; v1 -= v0; - u2 -= u0; v2 -= v0; - - det = u1 * v2 - u2 * v1; - - if ( det === 0 ) return; - - idet = 1 / det; - - a = ( v2 * x1 - v1 * x2 ) * idet; - b = ( v2 * y1 - v1 * y2 ) * idet; - c = ( u1 * x2 - u2 * x1 ) * idet; - d = ( u1 * y2 - u2 * y1 ) * idet; - - e = x0 - a * u0 - c * v0; - f = y0 - b * u0 - d * v0; - - _context.save(); - _context.transform( a, b, c, d, e, f ); - _context.fill(); - _context.restore(); - - } - - function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) { - - // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 - - var a, b, c, d, e, f, det, idet, - width = image.width - 1, - height = image.height - 1; - - u0 *= width; v0 *= height; - u1 *= width; v1 *= height; - u2 *= width; v2 *= height; - - x1 -= x0; y1 -= y0; - x2 -= x0; y2 -= y0; - - u1 -= u0; v1 -= v0; - u2 -= u0; v2 -= v0; - - det = u1 * v2 - u2 * v1; - - idet = 1 / det; - - a = ( v2 * x1 - v1 * x2 ) * idet; - b = ( v2 * y1 - v1 * y2 ) * idet; - c = ( u1 * x2 - u2 * x1 ) * idet; - d = ( u1 * y2 - u2 * y1 ) * idet; - - e = x0 - a * u0 - c * v0; - f = y0 - b * u0 - d * v0; - - _context.save(); - _context.transform( a, b, c, d, e, f ); - _context.clip(); - _context.drawImage( image, 0, 0 ); - _context.restore(); - - } - - function getGradientTexture( color1, color2, color3, color4 ) { - - // http://mrdoob.com/blog/post/710 - - _pixelMapData[ 0 ] = ( color1.r * 255 ) | 0; - _pixelMapData[ 1 ] = ( color1.g * 255 ) | 0; - _pixelMapData[ 2 ] = ( color1.b * 255 ) | 0; - - _pixelMapData[ 4 ] = ( color2.r * 255 ) | 0; - _pixelMapData[ 5 ] = ( color2.g * 255 ) | 0; - _pixelMapData[ 6 ] = ( color2.b * 255 ) | 0; - - _pixelMapData[ 8 ] = ( color3.r * 255 ) | 0; - _pixelMapData[ 9 ] = ( color3.g * 255 ) | 0; - _pixelMapData[ 10 ] = ( color3.b * 255 ) | 0; - - _pixelMapData[ 12 ] = ( color4.r * 255 ) | 0; - _pixelMapData[ 13 ] = ( color4.g * 255 ) | 0; - _pixelMapData[ 14 ] = ( color4.b * 255 ) | 0; - - _pixelMapContext.putImageData( _pixelMapImage, 0, 0 ); - _gradientMapContext.drawImage( _pixelMap, 0, 0 ); - - return _gradientMap; - - } - - // Hide anti-alias gaps - - function expand( v1, v2, pixels ) { - - var x = v2.x - v1.x, y = v2.y - v1.y, - det = x * x + y * y, idet; - - if ( det === 0 ) return; - - idet = pixels / Math.sqrt( det ); - - x *= idet; y *= idet; - - v2.x += x; v2.y += y; - v1.x -= x; v1.y -= y; - - } - - // Context cached methods. - - function setOpacity( value ) { - - if ( _contextGlobalAlpha !== value ) { - - _context.globalAlpha = value; - _contextGlobalAlpha = value; - - } - - } - - function setBlending( value ) { - - if ( _contextGlobalCompositeOperation !== value ) { - - if ( value === THREE.NormalBlending ) { - - _context.globalCompositeOperation = 'source-over'; - - } else if ( value === THREE.AdditiveBlending ) { - - _context.globalCompositeOperation = 'lighter'; - - } else if ( value === THREE.SubtractiveBlending ) { - - _context.globalCompositeOperation = 'darker'; - - } - - _contextGlobalCompositeOperation = value; - - } - - } - - function setLineWidth( value ) { - - if ( _contextLineWidth !== value ) { - - _context.lineWidth = value; - _contextLineWidth = value; - - } - - } - - function setLineCap( value ) { - - // "butt", "round", "square" - - if ( _contextLineCap !== value ) { - - _context.lineCap = value; - _contextLineCap = value; - - } - - } - - function setLineJoin( value ) { - - // "round", "bevel", "miter" - - if ( _contextLineJoin !== value ) { - - _context.lineJoin = value; - _contextLineJoin = value; - - } - - } - - function setStrokeStyle( value ) { - - if ( _contextStrokeStyle !== value ) { - - _context.strokeStyle = value; - _contextStrokeStyle = value; - - } - - } - - function setFillStyle( value ) { - - if ( _contextFillStyle !== value ) { - - _context.fillStyle = value; - _contextFillStyle = value; - - } - - } - - function setDashAndGap( dashSizeValue, gapSizeValue ) { - - if ( _contextDashSize !== dashSizeValue || _contextGapSize !== gapSizeValue ) { - - _context.setLineDash( [ dashSizeValue, gapSizeValue ] ); - _contextDashSize = dashSizeValue; - _contextGapSize = gapSizeValue; - - } - - } - -}; - -/** - * Shader chunks for WebLG Shader library - * - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author bhouston / http://clara.io/ - */ - -THREE.ShaderChunk = { - - // FOG - - common: [ - - "#define PI 3.14159", - "#define PI2 6.28318", - "#define LOG2 1.442695", - "#define ENCODING_Linear 3000", - "#define ENCODING_sRGB 3001", - "#define ENCODING_RGBE 3002", - "#define ENCODING_RGBM7 3004", - "#define ENCODING_RGBM16 3005", - "#define SPECULAR_COEFF 0.18", - "float square( float a ) { return a*a; }", - "vec2 square( vec2 a ) { return vec2( a.x*a.x, a.y*a.y ); }", - "vec3 square( vec3 a ) { return vec3( a.x*a.x, a.y*a.y, a.z*a.z ); }", - "vec4 square( vec4 a ) { return vec4( a.x*a.x, a.y*a.y, a.z*a.z, a.w*a.w ); }", - "float saturate( float a ) { return clamp( a, 0.0, 1.0 ); }", - "vec2 saturate( vec2 a ) { return clamp( a, 0.0, 1.0 ); }", - "vec3 saturate( vec3 a ) { return clamp( a, 0.0, 1.0 ); }", - "vec4 saturate( vec4 a ) { return clamp( a, 0.0, 1.0 ); }", - "float average( float a ) { return a; }", - "float average( vec2 a ) { return ( a.x + a.y) * 0.5; }", - "float average( vec3 a ) { return ( a.x + a.y + a.z) * 0.3333333333; }", - "float average( vec4 a ) { return ( a.x + a.y + a.z + a.w) * 0.25; }", - "float whiteCompliment( float a ) { return saturate( 1.0 - a ); }", - "vec2 whiteCompliment( vec2 a ) { return saturate( vec2(1.0) - a ); }", - "vec3 whiteCompliment( vec3 a ) { return saturate( vec3(1.0) - a ); }", - "vec4 whiteCompliment( vec4 a ) { return saturate( vec4(1.0) - a ); }", - "vec3 projectOnPlane( vec3 point, vec3 pointOnPlane, vec3 planeNormal) {", - "float distance = dot( planeNormal, point-pointOnPlane );", - "return point - distance * planeNormal;", - "}", - "float sideOfPlane( vec3 point, vec3 pointOnPlane, vec3 planeNormal ) {", - "return sign( dot( point - pointOnPlane, planeNormal ) );", - "}", - "vec2 applyUVOffsetRepeat( vec2 uv, vec4 offsetRepeat ) {", - "return uv * offsetRepeat.zw + offsetRepeat.xy;", - "}", - "vec3 linePlaneIntersect( vec3 pointOnLine, vec3 lineDirection, vec3 pointOnPlane, vec3 planeNormal ) {", - "return pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) );", - "}", - "vec4 applyGainBrightness( vec4 texel, vec4 gainBrightnessCoeff ) {", - "if( gainBrightnessCoeff.w < 0.0 ) {", - "texel.xyz = whiteCompliment( texel.xyz );", - "}", - "texel.xyz = ( texel.xyz - vec3( gainBrightnessCoeff.x ) ) * gainBrightnessCoeff.y + vec3( gainBrightnessCoeff.z + gainBrightnessCoeff.x );", - "return texel;", - "}", - "vec4 texelDecode( vec4 texel, int encoding ) {", - - "if( encoding == 3001 ) {", // sRGB - "texel = vec4( pow( max( texel.xyz, vec3( 0.0 ) ), vec3( 2.2 ) ), texel.w );", - "}", - - "else if( encoding == 3002 ) {", // RGBE / Radiance - "texel = vec4( texel.xyz * pow( 2.0, texel.w*256.0 - 128.0 ), 1.0 );", - "}", - - // TODO LogLUV decoding. - - "else if( encoding == 3004 ) {", // RGBM 7.0 / Marmoset - "texel = vec4( texel.xyz * texel.w * 7.0, 1.0 );", - "}", - - "else if( encoding == 3005 ) {", // RGBM 16 - "texel = vec4( texel.xyz * texel.w * 16.0, 1.0 );", - "}", - - "return texel;", - "}", - ].join("\n"), - - // FOG - - fog_pars_fragment: [ - - "#ifdef USE_FOG", - - "uniform vec3 fogColor;", - - "#ifdef FOG_EXP2", - - "uniform float fogDensity;", - - "#else", - - "uniform float fogNear;", - "uniform float fogFar;", - - "#endif", - - "#endif" - - ].join("\n"), - - fog_fragment: [ - - "#ifdef USE_FOG", - - "float depth = gl_FragCoord.z / gl_FragCoord.w;", - - "#ifdef FOG_EXP2", - - "float fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );", - "fogFactor = 1.0 - saturate( fogFactor );", - - "#else", - - "float fogFactor = smoothstep( fogNear, fogFar, depth );", - - "#endif", - - "gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );", - - "#endif" - - ].join("\n"), - - // DIFFUSE ENVIRONMENT MAP - - diffuseenvmap_pars_fragment: [ - - "#if defined( USE_DIFFUSEENVMAP )", - - "uniform samplerCube diffuseEnvMap;", - "uniform int diffuseEnvEncoding;", - - "#endif" - - ].join("\n"), - - // ENVIRONMENT MAP - - envmap_pars_fragment: [ - - "#if defined( USE_DIFFUSEENVMAP ) || defined( USE_ENVMAP )", - - "uniform float flipEnvMap;", - - "#endif", - - "#ifdef USE_ENVMAP", - - "uniform float reflectivity;", - "uniform samplerCube envMap;", - "uniform int combine;", - "uniform int envEncoding;", - - "#endif" - - ].join("\n"), - - envmap_fragment: [ - - "#if defined( USE_ENVMAP ) && ! defined( PHYSICAL )", - - "vec3 worldNormal = vec3( normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz ) );", - "vec3 worldView = -vec3( normalize( ( vec4( viewDirection, 0.0 ) * viewMatrix ).xyz ) );", - - "vec3 reflectVec = reflect( worldView, worldNormal );", - - "#ifdef DOUBLE_SIDED", - - "float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );", - - "vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", - - "#else", - - "vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", - - "#endif", - - "cubeColor = texelDecode( cubeColor, envEncoding );", - - "float fresnelReflectivity = saturate( reflectivity );", - - "if ( combine == 1 ) {", - - "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, fresnelReflectivity );", - - "} else if ( combine == 2 ) {", - - "gl_FragColor.xyz += cubeColor.xyz * fresnelReflectivity;", - - "} else {", - - "gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, fresnelReflectivity );", - - "}", - - "#endif" - - ].join("\n"), - - worldpos_vertex : [ - - "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )", - - "#ifdef USE_SKINNING", - - "vec4 worldPosition = modelMatrix * skinned;", - - "#endif", - - "#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", - - "vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );", - - "#endif", - - "#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", - - "vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", - - "#endif", - - "#endif" - - ].join("\n"), - - // COLOR MAP (particles) - - map_particle_pars_fragment: [ - - "#ifdef USE_MAP", - - "uniform sampler2D map;", - - "#endif" - - ].join("\n"), - - - map_particle_fragment: [ - - "#ifdef USE_MAP", - - "gl_FragColor = gl_FragColor * texelDecode( texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) ), ENCODING_sRGB );", - - "#endif" - - ].join("\n"), - - // COLOR MAP (triangles) - - map_pars_vertex: [ - - "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )", - - "varying vec2 vUv;", - - "#endif" - - ].join("\n"), - - map_pars_fragment: [ - - "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )", - - "varying vec2 vUv;", - "uniform vec4 offsetRepeat;", - "uniform vec4 gainBrightness;", - - "#endif", - - "#ifdef USE_MAP", - - "uniform sampler2D map;", - - "#endif" - - ].join("\n"), - - map_vertex: [ - - "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )", - - "vUv = uv;", - - "#endif" - - ].join("\n"), - - map_fragment: [ - - "#if defined( USE_MAP ) || defined( USE_FALLOFFMAP )", - - "vec2 vUvLocal = applyUVOffsetRepeat( vUv, offsetRepeat );", - - "#endif", - - "#ifdef USE_MAP", - - "vec4 texelColor = clamp( applyGainBrightness( texelDecode( texture2D( map, vUvLocal ), ENCODING_sRGB ), gainBrightness ), vec4(0.0), vec4(1.0) );", - - "gl_FragColor = gl_FragColor * texelColor;", - - "#if defined( PHYSICAL ) || defined( PHONG )", - - "diffuseColor *= texelColor.xyz;", - - "#endif", // PHYSICAL - - "#endif" - - ].join("\n"), - - // FALLOFF MAP - - falloffmap_pars_fragment: [ - - "#ifdef USE_FALLOFFMAP", - - "uniform sampler2D falloffMap;", - - "#endif" - - ].join("\n"), - - // OPACITY MAP - - opacitymap_pars_fragment: [ - - "#ifdef USE_OPACITYMAP", - - "uniform sampler2D opacityMap;", - "uniform vec4 opacityOffsetRepeat;", - "uniform vec4 opacityGainBrightness;", - - "#endif" - - ].join("\n"), - - - opacitymap_fragment: [ - - "#ifdef USE_OPACITYMAP", - - "vec2 vOpacityUv = applyUVOffsetRepeat( vUv, opacityOffsetRepeat );", - "vec4 texelOpacity = applyGainBrightness( texture2D( opacityMap, vOpacityUv ), opacityGainBrightness );", - - "gl_FragColor.w = clamp( gl_FragColor.w * texelOpacity.r, 0.0, 1.0 );", - - "#endif" - - ].join("\n"), - - // TRANSLUCENCY MAP - - translucencymap_pars_fragment: [ - - "#ifdef USE_TRANSLUCENCYMAP", - - "uniform sampler2D translucencyMap;", - "uniform vec4 translucencyOffsetRepeat;", - "uniform vec4 translucencyGainBrightness;", - - "#endif" - - ].join("\n"), - - translucencymap_fragment: [ - - "#ifdef USE_TRANSLUCENCYMAP", - - "vec2 vTranslucencyUv = applyUVOffsetRepeat( vUv, translucencyOffsetRepeat );", - "vec4 texelTranslucency = applyGainBrightness( texture2D( translucencyMap, vTranslucencyUv ), translucencyGainBrightness );", - - "translucencyColor.xyz = clamp( translucencyColor.xyz * texelTranslucency.xyz, vec3( 0.0 ), vec3( 1.0 ) );", - - "#endif" - - ].join("\n"), - - // LIGHT MAP - - lightmap_pars_fragment: [ - - "#if defined( USE_LIGHTMAP ) || defined( USE_EMISSIVEMAP )", - - "varying vec2 vUv2;", - - "#endif", - - "#if defined( USE_LIGHTMAP )", - - "uniform sampler2D lightMap;", - - "#endif", - - "#if defined( USE_EMISSIVEMAP )", - - "uniform sampler2D emissiveMap;", - - "#endif" - - ].join("\n"), - - lightmap_pars_vertex: [ - - "#if defined( USE_LIGHTMAP ) || defined( USE_EMISSIVEMAP )", - - "varying vec2 vUv2;", - - "#endif" - - ].join("\n"), - - lightmap_fragment: [ - - "#ifdef USE_LIGHTMAP", - - //"gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );", - - "#endif" - - ].join("\n"), - - lightmap_vertex: [ - - "#if defined( USE_LIGHTMAP ) || defined( USE_EMISSIVEMAP )", - - "vUv2 = uv2;", - - "#endif" - - ].join("\n"), - - - // BUMP MAP - - bumpmap_pars_fragment: [ - - "#ifdef USE_BUMPMAP", - - "uniform sampler2D bumpMap;", - "uniform vec4 bumpOffsetRepeat;", - "uniform float bumpScale;", - - // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen - // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html - - // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2) - - "vec2 dHdxy_fwd() {", - - "#ifdef GL_OES_standard_derivatives", - - "vec2 vBumpUv = applyUVOffsetRepeat( vUv, bumpOffsetRepeat );", - - "vec2 dSTdx = dFdx( vBumpUv );", - "vec2 dSTdy = dFdy( vBumpUv );", - - "float Hll = bumpScale * texture2D( bumpMap, vBumpUv ).x;", - "float dBx = bumpScale * texture2D( bumpMap, vBumpUv + dSTdx ).x - Hll;", - "float dBy = bumpScale * texture2D( bumpMap, vBumpUv + dSTdy ).x - Hll;", - - "return vec2( dBx, dBy );", - - "#else", - - "return vec2( 0.0, 0.0 );", - - "#endif", - - "}", - - "vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {", - - "#ifdef GL_OES_standard_derivatives", - - "vec3 vSigmaX = dFdx( surf_pos );", - "vec3 vSigmaY = dFdy( surf_pos );", - "vec3 vN = surf_norm;", // normalized - - "vec3 R1 = cross( vSigmaY, vN );", - "vec3 R2 = cross( vN, vSigmaX );", - - "float fDet = dot( vSigmaX, R1 );", - - "vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );", - "return normalize( abs( fDet ) * surf_norm - vGrad );", - - "#else", - - "return surf_norm;", - - "#endif", - - "}", - - "#endif" - - ].join("\n"), - - // LIGHT ATTENUATION function - - lightattenuation_func_fragment: [ - - "float calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {", - "if ( decayExponent > 0.0 && cutoffDistance > 0.0 ) {", - "return pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );", - "}", - "else if ( decayExponent < 0.0 ) {", - // this is based upon UE4 light fall as described on page 11 of: - // https://de45xmedrsdbp.cloudfront.net/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf - "float numerator = 1.0;", - "if( cutoffDistance > 0.0 ) {", - "numerator = ( saturate( 1.0 - pow( lightDistance / cutoffDistance, 4.0 ) ) );", - "numerator *= numerator;", - "} ", - "return numerator / ( ( lightDistance * lightDistance ) + 1.0 );", - "}", - "else {", - "return 1.0;", - "}", - - /*"float distanceAttenuation = 1.0 / pow( max( lightDistance, 0.0 ), decayExponent );", - "if ( cutoffDistance > 0.0 ) {", - "distanceAttenuation *= 1.0 - min( lightDistance / cutoffDistance, 1.0 );", - "}", - "return distanceAttenuation;",*/ - "}", - - - ].join("\n"), - - // NORMAL MAP - - normalmap_pars_fragment: [ - - "#ifdef USE_NORMALMAP", - - "uniform sampler2D normalMap;", - "uniform vec4 normalOffsetRepeat;", - "uniform vec2 normalScale;", - - // Per-Pixel Tangent Space Normal Mapping - // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html - - "vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {", - - "#ifdef GL_OES_standard_derivatives", - - "vec2 vNormalUv = applyUVOffsetRepeat( vUv, normalOffsetRepeat );", - - "vec3 q0 = dFdx( eye_pos.xyz );", - "vec3 q1 = dFdy( eye_pos.xyz );", - "vec2 st0 = dFdx( vNormalUv.st );", - "vec2 st1 = dFdy( vNormalUv.st );", - - "vec3 S = normalize( q0 * st1.t - q1 * st0.t );", - "vec3 T = normalize( -q0 * st1.s + q1 * st0.s );", - "vec3 N = normalize( surf_norm );", - - "vec3 mapN = texture2D( normalMap, vNormalUv ).xyz * 2.0 - 1.0;", - "mapN.xy = normalScale * mapN.xy;", - "mat3 tsn = mat3( S, T, N );", - "return normalize( tsn * mapN );", - - "#else", - - "return surf_norm;", - - "#endif", - - "}", - - "#endif" - - ].join("\n"), - - // ANISOTROPY MAP - - anisotropymap_pars_fragment: [ - - "#ifdef USE_ANISOTROPYMAP", - - "uniform sampler2D anisotropyMap;", - "uniform vec4 anisotropyGainBrightness;", - "uniform vec4 anisotropyOffsetRepeat;", - - "#endif" - ].join("\n"), - - anisotropymap_fragment: [ - - "#ifdef USE_ANISOTROPYMAP", - - "vec2 vAnisotropyUv = applyUVOffsetRepeat( vUv, anisotropyOffsetRepeat );", - - "#else", - - "#ifdef ANISOTROPY", - - "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )", - - "vec2 vAnisotropyUv = vUv;", - - "#else", - - "vec2 vAnisotropyUv = vec2( 0, 0 );", - - "#endif", - - "#endif", - - "#endif", - - "float anisotropyStrength = anisotropy;", - - "#ifdef USE_ANISOTROPYMAP", - - "vec4 texelAnisotropy = applyGainBrightness( texture2D( anisotropyMap, vAnisotropyUv ), anisotropyGainBrightness );", - "anisotropyStrength = clamp( anisotropyStrength + texelAnisotropy.r, -1.0, 1.0 );", - - "#endif" - - ].join("\n"), - - // ANISOTROPY ROTATION MAP - - anisotropyrotationmap_pars_fragment: [ - - "#ifdef USE_ANISOTROPYROTATIONMAP", - - "uniform sampler2D anisotropyRotationMap;", - "uniform vec4 anisotropyRotationGainBrightness;", - "uniform vec4 anisotropyRotationOffsetRepeat;", - - "#endif" - - ].join("\n"), - - anisotropyrotationmap_fragment: [ - - "float anisotropyRotationStrength = anisotropyRotation;", - - "#ifdef USE_ANISOTROPYROTATIONMAP", - - "vec2 vAnisotropyRotationUv = applyUVOffsetRepeat( vUv, anisotropyRotationOffsetRepeat );", - "vec4 texelAnisotropyRotation = applyGainBrightness( texture2D( anisotropyRotationMap, vAnisotropyRotationUv ), anisotropyRotationGainBrightness );", - "anisotropyRotationStrength += texelAnisotropyRotation.r;", - - "#endif" - - ].join("\n"), - - // METALLIC MAP - - metallicmap_pars_fragment: [ - - "#ifdef USE_METALLICMAP", - - "uniform sampler2D metallicMap;", - "uniform vec4 metallicGainBrightness;", - "uniform vec4 metallicOffsetRepeat;", - - "#endif" - - ].join("\n"), - - metallicmap_fragment: [ - - "float metallicStrength = metallic;", - - "#ifdef USE_METALLICMAP", - - "vec2 vMetallicUv = applyUVOffsetRepeat( vUv, metallicOffsetRepeat );", - "vec4 texelMetallic = applyGainBrightness( texture2D( metallicMap, vMetallicUv ), metallicGainBrightness );", - "metallicStrength = clamp( metallicStrength * texelMetallic.r, 0.0, 1.0 );", - - "#endif" - - ].join("\n"), - - // ROUGHNESS MAP - - roughnessmap_pars_fragment: [ - - "#ifdef USE_ROUGHNESSMAP", - - "uniform sampler2D roughnessMap;", - "uniform vec4 roughnessOffsetRepeat;", - "uniform vec4 roughnessGainBrightness;", - - "#endif" - - ].join("\n"), - - roughnessmap_fragment: [ - - "float roughnessStrength = roughness;", - - "#ifdef USE_ROUGHNESSMAP", - - "vec2 vRoughnessUv = applyUVOffsetRepeat( vUv, roughnessOffsetRepeat );", - "vec4 texelRoughness = applyGainBrightness( texture2D( roughnessMap, vRoughnessUv ), roughnessGainBrightness );", - "roughnessStrength = clamp( roughnessStrength * texelRoughness.r, 0.0, 1.0 );", - - "#endif" - - ].join("\n"), - - // SPECULAR MAP - - specularmap_pars_fragment: [ - - "#ifdef USE_SPECULARMAP", - - "uniform sampler2D specularMap;", - "uniform vec4 specularGainBrightness;", - "uniform vec4 specularOffsetRepeat;", - - "#endif" - - ].join("\n"), - - specularmap_fragment: [ - - "#ifdef PHYSICAL", - "vec3 specularColor = specular;", - "#else", - "float specularStrength = 1.0;", - "#endif", - - "#ifdef USE_SPECULARMAP", - - "vec2 vSpecularUv = applyUVOffsetRepeat( vUv, specularOffsetRepeat );", - "vec4 texelSpecular = applyGainBrightness( texelDecode( texture2D( specularMap, vSpecularUv ), ENCODING_sRGB ), specularGainBrightness );", - - "#ifdef PHYSICAL", - "specularColor.rgb = clamp( specularColor.rgb * texelSpecular.rgb, vec3( 0.0 ), vec3( 1.0 ) );", - "#else", - "specularStrength = clamp( specularStrength * texelSpecular.r, 0.0, 1.0 );", - "#endif", - - "#endif", - - ].join("\n"), - - // LIGHTS LAMBERT - - lights_lambert_pars_vertex: [ - - "uniform vec3 ambient;", - "uniform vec3 diffuse;", - "uniform vec3 emissive;", - - "uniform vec3 ambientLightColor;", - - "#if MAX_DIR_LIGHTS > 0", - - "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", - "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", - - "#endif", - - "#if MAX_HEMI_LIGHTS > 0", - - "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", - - "#endif", - - "#if MAX_POINT_LIGHTS > 0", - - "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", - "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", - "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", - "uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];", - - "#endif", - - "#if MAX_SPOT_LIGHTS > 0", - - "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightDecayExponent[ MAX_SPOT_LIGHTS ];", - - "#endif", - - "#if MAX_AREA_LIGHTS > 0", - - "uniform vec3 areaLightColor[ MAX_AREA_LIGHTS ];", - "uniform vec3 areaLightPosition[ MAX_AREA_LIGHTS ];", - "uniform vec3 areaLightWidth[ MAX_AREA_LIGHTS ];", - "uniform vec3 areaLightHeight[ MAX_AREA_LIGHTS ];", - "uniform float areaLightDistance[ MAX_AREA_LIGHTS ];", - "uniform float areaLightDecayExponent[ MAX_AREA_LIGHTS ];", - - "#endif", - - "#ifdef WRAP_AROUND", - - "uniform vec3 wrapRGB;", - - "#endif" - - ].join("\n"), - - lights_lambert_vertex: [ - - "vLightFront = vec3( 0.0 );", - - "#ifdef DOUBLE_SIDED", - - "vLightBack = vec3( 0.0 );", - - "#endif", - - "transformedNormal = normalize( transformedNormal );", - - "#if MAX_DIR_LIGHTS > 0", - - "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", - - "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", - "vec3 dirVector = normalize( lDirection.xyz );", - - "float dotProduct = dot( transformedNormal, dirVector );", - "vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );", - - "#ifdef DOUBLE_SIDED", - - "vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", - - "#ifdef WRAP_AROUND", - - "vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", - - "#endif", - - "#endif", - - "#ifdef WRAP_AROUND", - - "vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", - "directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );", - - "#ifdef DOUBLE_SIDED", - - "directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );", - - "#endif", - - "#endif", - - "vLightFront += directionalLightColor[ i ] * directionalLightWeighting;", - - "#ifdef DOUBLE_SIDED", - - "vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;", - - "#endif", - - "}", - - "#endif", - - "#if MAX_POINT_LIGHTS > 0", - - "for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", - - "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", - "vec3 lVector = lPosition.xyz - mvPosition.xyz;", - - "float distanceAttenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );", - - "lVector = normalize( lVector );", - "float dotProduct = dot( transformedNormal, lVector );", - - "vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );", - - "#ifdef DOUBLE_SIDED", - - "vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", - - "#ifdef WRAP_AROUND", - - "vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", - - "#endif", - - "#endif", - - "#ifdef WRAP_AROUND", - - "vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", - "pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );", - - "#ifdef DOUBLE_SIDED", - - "pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );", - - "#endif", - - "#endif", - - "vLightFront += pointLightColor[ i ] * pointLightWeighting * distanceAttenuation;", - - "#ifdef DOUBLE_SIDED", - - "vLightBack += pointLightColor[ i ] * pointLightWeightingBack * distanceAttenuation;", - - "#endif", - - "}", - - "#endif", - - "#if MAX_SPOT_LIGHTS > 0", - - "for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", - - "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", - "vec3 lVector = lPosition.xyz - mvPosition.xyz;", - - "float distanceAttenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );", - - "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );", - - "if ( spotEffect > spotLightAngleCos[ i ] ) {", - - "spotEffect = pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] );", - - "lVector = normalize( lVector );", - - "float dotProduct = dot( transformedNormal, lVector );", - "vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );", - - "#ifdef DOUBLE_SIDED", - - "vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", - - "#ifdef WRAP_AROUND", - - "vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", - - "#endif", - - "#endif", - - "#ifdef WRAP_AROUND", - - "vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", - "spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );", - - "#ifdef DOUBLE_SIDED", - - "spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );", - - "#endif", - - "#endif", - - "vLightFront += spotLightColor[ i ] * spotLightWeighting * distanceAttenuation * spotEffect;", - - "#ifdef DOUBLE_SIDED", - - "vLightBack += spotLightColor[ i ] * spotLightWeightingBack * distanceAttenuation * spotEffect;", - - "#endif", - - "}", - - "}", - - "#endif", - - "#if MAX_HEMI_LIGHTS > 0", - - "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", - - "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", - "vec3 lVector = normalize( lDirection.xyz );", - - "float dotProduct = dot( transformedNormal, lVector );", - - "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", - "float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;", - - "vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", - - "#ifdef DOUBLE_SIDED", - - "vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );", - - "#endif", - - "}", - - "#endif", - - "vLightFront = ( vLightFront + ambientLightColor + ambient) * diffuse + emissive;", - - "#ifdef DOUBLE_SIDED", - - "vLightBack = ( vLightFront + ambientLightColor + ambient) * diffuse + emissive;", - - "#endif" - - ].join("\n"), - - // LIGHTS PHYSICAL - - lights_physical_pars_vertex: [ - - "#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", - - "varying vec3 vWorldPosition;", - - "#endif" - - ].join("\n"), - - - lights_physical_vertex: [ - - "#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", - - "vWorldPosition = worldPosition.xyz;", - - "#endif", - - "#ifdef USE_SKINNING", - - "vNormal = normalize( normalMatrix * skinnedNormal.xyz );", - - "vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );", - "vTangent = normalize( normalMatrix * skinnedTangent.xyz );", - - "#else", - - "vNormal = normalize( normalMatrix * normal );", - "vTangent = normalize( normalMatrix * tangent.xyz );", - - "#endif", - - "vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );", - - - ].join("\n"), - - lights_physical_pars_fragment: [ - - "uniform vec3 ambientLightColor;", - - "#if MAX_DIR_LIGHTS > 0", - - "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", - "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", - - "#endif", - - "#if MAX_HEMI_LIGHTS > 0", - - "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", - - "#endif", - - "#if MAX_POINT_LIGHTS > 0", - - "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", - "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", - "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", - "uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];", - - "#endif", - - "#if MAX_SPOT_LIGHTS > 0", - - "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightDecayExponent[ MAX_SPOT_LIGHTS ];", - - "#endif", - - "#if MAX_AREA_LIGHTS > 0", - - "uniform vec3 areaLightColor[ MAX_AREA_LIGHTS ];", - "uniform vec3 areaLightPosition[ MAX_AREA_LIGHTS ];", - "uniform vec3 areaLightWidth[ MAX_AREA_LIGHTS ];", - "uniform vec3 areaLightHeight[ MAX_AREA_LIGHTS ];", - "uniform float areaLightDistance[ MAX_AREA_LIGHTS ];", - "uniform float areaLightDecayExponent[ MAX_AREA_LIGHTS ];", - - "#endif", - - "#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP )", - - "varying vec3 vWorldPosition;", - - "#endif", - - "#ifdef WRAP_AROUND", - - "uniform vec3 wrapRGB;", - - "#endif", - - "varying vec3 vViewPosition;", - "varying vec3 vTangent;", - "varying vec3 vBinormal;", - "varying vec3 vNormal;", - - // classic Fresnel Schlick - /*"float Fresnel_Schlick( float hDotV ) {", - "float F0 = 0.04;", - "return F0 + ( 1.0 - F0 ) * pow( 1.0 - hDotV, 5.0 );", - "}",*/ - - // Calcuate the Fresnel term using the Schlick approximation (using Unreal's blend to white method) VALIDATED - "vec3 Fresnel_Schlick_SpecularBlendToWhite(vec3 specularColor, float hDotV) {", - "float Fc = pow(max( 1.0 - hDotV, 0.0 ), 5.0);", - "return saturate( 50.0 * average( specularColor ) ) * Fc + (1.0 - Fc) * specularColor;", - "}", - - "vec3 Fresnel_Schlick_SpecularBlendToWhiteRoughness(vec3 specularColor, float hDotV, float roughness) {", - "float Fc = pow(max( 1.0 - hDotV, 0.0 ), 5.0) / ( 1.0 + 3.0 * roughness );", - - "return mix( specularColor, vec3( saturate( 50.0 * average( specularColor ) ) ), Fc );", - "}", - - // Calculate the distribution term VALIDATED - "float Distribution_GGX( float roughness2, float nDotH ) {", - "float denom = nDotH * nDotH * (roughness2 - 1.0) + 1.0;", - "return roughness2 / ( PI * square( denom ) + 0.0000001 );", - "}", - - // Calculated the anisotropic GGZ distrubtion term VALIDATED - "float Distribution_GGXAniso( vec2 anisotropicM, vec2 xyDotH, float nDotH ) {", - "float anisoTerm = ( xyDotH.x * xyDotH.x / ( anisotropicM.x * anisotropicM.x ) + xyDotH.y * xyDotH.y / ( anisotropicM.y * anisotropicM.y ) + nDotH * nDotH );", - "return 1.0 / ( PI * anisotropicM.x * anisotropicM.y * anisoTerm * anisoTerm + 0.0000001 );", - "}", - - // useful for clear coat surfaces, use with Distribution_GGX. - "float Visibility_Kelemen( float vDotH ) {", - "return 1.0 / ( 4.0 * vDotH * vDotH + 0.0000001 );", - "}", - - "float Visibility_Schlick( float roughness2, float nDotL, float nDotV) {", - "float termL = (nDotL + sqrt(roughness2 + (1.0 - roughness2) * nDotL * nDotL));", - "float termV = (nDotV + sqrt(roughness2 + (1.0 - roughness2) * nDotV * nDotV));", - "return 1.0 / ( abs( termL * termV ) + 0.0000001 );", - "}", - - "float Diffuse_Lambert() {", - "return 1.0 / PI;", - "}", - - "float Diffuse_OrenNayer( float m2, float nDotV, float nDotL, float vDotH ) {", - "float termA = 1.0 - 0.5 * m2 / (m2 + 0.33);", - "float Cosri = 2.0 * vDotH - 1.0 - nDotV * nDotL;", - "float termB = 0.45 * m2 / (m2 + 0.09) * Cosri * ( Cosri >= 0.0 ? min( 1.0, nDotL / nDotV ) : nDotL );", - "return 1.0 / PI * ( nDotL * termA + termB );", - "}", - - // Helper for anisotropy rotation - "mat2 createRotationMat2( float rads) {", - "float cos_rads = cos( rads );", - "float sin_rads = sin( rads );", - "return mat2( vec2( cos_rads, sin_rads ), vec2( -sin_rads, cos_rads ) );", - "}", - - // Helper for anisotropy rotation - "vec2 calcAnisotropyUV( float anisotropyLocal) {", - "float oneMinusAbsAnisotropy = 1.0 - min( abs( anisotropyLocal ) * 0.9, 0.9 );", - "vec2 anisotropyUV = vec2 ( 1.0 / oneMinusAbsAnisotropy, oneMinusAbsAnisotropy );", - "if( anisotropy < 0.0 ) {", - "anisotropyUV.xy = anisotropyUV.yx;", // swizzel - "}", - "return anisotropyUV;", - "}" - - //"float horizonOcclusion( vec3 reflectionVector, vec3 originalNormal ) {", - // "return quare( saturate( 1.0 + uHorizonOcclude*dot( dir, vertexNormal ) ) );", - //"}" - - - ].join("\n"), - - lights_physical_fragment: [ - - "mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normal );", - - "#ifdef USE_NORMALMAP", - - "normal = perturbNormal2Arb( -vViewPosition, normal );", - - /*"vec3 normalTex = texture2D( normalMap, vNormalUv ).xyz * 2.0 - 1.0;", - "normalTex.xy *= normalScale;", - "normalTex = perturbNormal2Arb( -viewDirection, normal );", - - "normal = tsb * normalTex;",*/ - - //"vec3 originalNormal = normal;", - "#endif", - - "#if defined( USE_BUMPMAP )", - - "normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );", - - "#endif", - - "#ifdef DOUBLE_SIDED", - - "normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );", - - "#endif", - - "#ifdef FALLOFF", - - "vec3 modulatedFalloffColor = falloffColor;", - - "#ifdef USE_FALLOFFMAP", - - "vec4 falloffTexelColor = texelDecode( texture2D( falloffMap, vUvLocal ), ENCODING_sRGB );", - - "modulatedFalloffColor = modulatedFalloffColor * falloffTexelColor.xyz;", - - "#endif", - - "float fm = abs( dot( normal, viewDirection ) );", - - // this is a hack, it needs to be fixed. - "fm = /*falloffBlendParams.x * fm + falloffBlendParams.y * */ ( fm * fm * ( 3.0 - 2.0 * fm ) );", - - "diffuseColor = mix( modulatedFalloffColor, diffuseColor, fm );", - - "#endif", - - "float nDotV = saturate( dot( normal, viewDirection ) );", - "float m2 = pow( clamp( roughnessStrength, 0.02, 1.0 ), 4.0 );", - // specular is scaled by 0.08 per Disney PBR recommendations. - "float m2ClearCoat = pow( clamp( clearCoatRoughness, 0.02, 1.0 ), 4.0 );", - - "specularColor = mix( specularColor * SPECULAR_COEFF, diffuseColor, metallicStrength );", - "diffuseColor *= ( 1.0 - metallicStrength );", - - "#ifdef ANISOTROPY", - - "vec2 anisotropicM = calcAnisotropyUV( anisotropyStrength ) * sqrt( m2 );", - - "#ifdef ANISOTROPYROTATION", - "mat2 anisotropicRotationMatrix = createRotationMat2( anisotropyRotationStrength * 2.0 * PI );", - "#endif", - - "vec3 anisotropicS = tsb[1];", // binormal in eye space. - "vec3 anisotropicT = tsb[0];", // tangent in eye space. - - "#endif", - - "vec3 totalLighting = vec3( 0.0 );", - - "#if ( defined( USE_ENVMAP ) || defined( USE_DIFFUSEENVMAP ) ) && defined( PHYSICAL )", - - "{", - - "vec3 worldNormal = vec3( normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz ) );", - "vec3 worldView = -vec3( normalize( ( vec4( viewDirection, 0.0 ) * viewMatrix ).xyz ) );", - - "vec3 reflectVec = reflect( worldView, worldNormal );", - - "vec3 hVector = normal;//normalize( viewDirection.xyz + lVector.xyz );", - "float nDotH = saturate( dot( normal, normal ) );", - "float hDotV = saturate( dot( normal, viewDirection ) );", - "float nDotL = hDotV;//saturate( dot( normal, lVector ) );", - - - "vec3 queryVector = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );", - - "#ifdef DOUBLE_SIDED", - - "queryVector *= ( -1.0 + 2.0 * float( gl_FrontFacing ) );", - - "#endif", - - "vec3 worldEnvNormal = vec3( normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz ) );", - "worldEnvNormal = vec3( flipEnvMap * worldEnvNormal.x, worldEnvNormal.yz );", - - "#ifdef DOUBLE_SIDED", - - "worldEnvNormal *= ( -1.0 + 2.0 * float( gl_FrontFacing ) );", - - "#endif", - - // calculate diffuse map contribution - - "vec4 diffuseEnvColor = vec4( 0.0, 0.0, 0.0, 1.0 );", - - "#if defined( USE_DIFFUSEENVMAP )", - - "diffuseEnvColor = texelDecode( textureCube( diffuseEnvMap, worldEnvNormal ), diffuseEnvEncoding );", - - "#elif defined( USE_ENVMAP )", - - "#if defined( TEXTURE_CUBE_LOD_EXT )", - - "diffuseEnvColor = texelDecode( textureCubeLodEXT( envMap, worldEnvNormal, 9.5 ), envEncoding );", - - "#else", - - "diffuseEnvColor = texelDecode( textureCube( envMap, worldEnvNormal, 10.0 ), envEncoding );", - - "#endif", - - "#endif", - - // calculate specular map contribution - - "vec4 specularEnvColor = vec4( 0.0, 0.0, 0.0, 1.0 );", - - "#if defined( USE_ENVMAP )", - - "#if defined( TEXTURE_CUBE_LOD_EXT )", - - "float specularMIPLevel = 9.7925 - 0.5 * log2( 2.0 / ( roughness * roughness + 0.00001 ) - 1.0 );", - "specularEnvColor = texelDecode( textureCubeLodEXT( envMap, queryVector, specularMIPLevel ), envEncoding );", - - "#else", - - "specularEnvColor = mix( texelDecode( textureCube( envMap, queryVector ), envEncoding ), texelDecode( textureCube( envMap, queryVector, 10.0 ), envEncoding ), roughnessStrength );", - - "#endif", - - "#endif", - - "vec3 specClearCoat = vec3(0, 0, 0);", - - "#if defined( CLEARCOAT ) && defined( USE_ENVMAP )", - - "#if defined( TEXTURE_CUBE_LOD_EXT )", - - "float clearCoatMIPLevel = 9.7925 - 0.5 * log2( 2.0 / ( clearCoatRoughness * clearCoatRoughness + 0.00001 ) - 1.0 );", - "vec4 specularClearCoatEnvColor = texelDecode( textureCubeLodEXT( envMap, queryVector, clearCoatMIPLevel ), envEncoding );", - - "#else", - - "vec4 specularClearCoatEnvColor = mix( texelDecode( textureCube( envMap, queryVector ), envEncoding ), texelDecode( textureCube( envMap, queryVector, 10.0 ), envEncoding ), clearCoatRoughness );", - - "#endif", - - "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhiteRoughness( vec3( SPECULAR_COEFF ), nDotL, m2ClearCoat );", - "specClearCoat = specularClearCoatEnvColor.rgb * fresnelClearCoat;", - - "#endif", - - "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhiteRoughness( specularColor, nDotL, m2 );", - - // Put it all together - "vec3 spec = fresnelColor * specularEnvColor.rgb;", - "vec3 diff = diffuseColor * diffuseEnvColor.rgb;", // no Diffuse_Lambert() term, it is baked into irradiance. - - "vec3 shadingResult = spec + diff;", - - "#ifdef CLEARCOAT", - - "shadingResult = mix( shadingResult, specClearCoat, clearCoat );", - - "#endif", - // diffuse - "totalLighting += shadingResult;", - - "}", - - "#endif", - - "#if MAX_POINT_LIGHTS > 0", - - "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", - - "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", - "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", - - "float distanceAttenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );", - - "vec3 incidentLight = pointLightColor[ i ] * distanceAttenuation;", - - "lVector = normalize( lVector );", - - // diffuse - - "vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );", - "float nDotH = saturate( dot( normal, hVector ) );", - "float nDotL = saturate( dot( normal, lVector ) );", - "float hDotV = saturate( dot( hVector, viewDirection ) );", - - "#ifdef CLEARCOAT", - - "float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );", - "float visClearCoat = Visibility_Kelemen( hDotV );", - "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );", - "vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;", - - "#endif", - - "#ifdef ANISOTROPY", - - "vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );", - - "#ifdef ANISOTROPYROTATION", - "xyDotH = anisotropicRotationMatrix * xyDotH;", - "#endif", - - "float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );", - - "#else", - - "float d = Distribution_GGX( m2, nDotH );", - - "#endif", - - "float vis = Visibility_Schlick(m2, nDotL, nDotV);", - "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );", - - // Put it all together - "vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;", - "vec3 diff = nDotL * Diffuse_Lambert() * diffuseColor;", - - "#ifdef TRANSLUCENCY", - - "diff *= whiteCompliment( translucencyColor.xyz );", - - "#endif", - - "vec3 shadingResult = spec + diff;", - - "#ifdef CLEARCOAT", - - "shadingResult = mix( shadingResult, specClearCoat, clearCoat );", - - "#endif", - // diffuse - "totalLighting += incidentLight * shadingResult;", - - "#ifdef TRANSLUCENCY", - - "float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );", - - "float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );", - - "totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;", - - "#endif", - - "}", - - "#endif", - - "#if MAX_SPOT_LIGHTS > 0", - - "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", - - "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", - "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", - - "float distanceAttenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );", - - "vec3 incidentLight = spotLightColor[ i ] * distanceAttenuation;", - - "lVector = normalize( lVector );", - - "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", - - "if ( spotEffect > spotLightAngleCos[ i ] ) {", - - "spotEffect = pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] );", - - // diffuse - - "incidentLight *= spotEffect;", - - "vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );", - "float nDotH = saturate( dot( normal, hVector ) );", - "float nDotL = saturate( dot( normal, lVector ) );", - "float hDotV = saturate( dot( hVector, viewDirection ) );", - - "#ifdef CLEARCOAT", - - "float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );", - "float visClearCoat = Visibility_Kelemen( hDotV );", - "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );", - "vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;", - - "#endif", - - "#ifdef ANISOTROPY", - - "vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );", - - "#ifdef ANISOTROPYROTATION", - "xyDotH = anisotropicRotationMatrix * xyDotH;", - "#endif", - - "float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );", - - "#else", - - "float d = Distribution_GGX( m2, nDotH );", - - "#endif", - - "float vis = Visibility_Schlick(m2, nDotL, nDotV);", - "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );", - - // Put it all together - "vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;", - "vec3 diff = nDotL * Diffuse_Lambert() * diffuseColor;", - - "#ifdef TRANSLUCENCY", - - "diff *= whiteCompliment( translucencyColor.xyz );", - - "#endif", - - "vec3 shadingResult = spec + diff;", - - "#ifdef CLEARCOAT", - - "shadingResult = mix( shadingResult, specClearCoat, clearCoat );", - - "#endif", - // diffuse - "totalLighting += incidentLight * shadingResult;", - - "#ifdef TRANSLUCENCY", - - "float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );", - - "float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );", - - "totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;", - - "#endif", - - "}", - - "}", - - "#endif", - - "#if MAX_DIR_LIGHTS > 0", - - "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", - - "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", - "vec3 lVector = normalize( lDirection.xyz );", - - "vec3 incidentLight = directionalLightColor[ i ];", - - "vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );", - "float nDotH = saturate( dot( normal, hVector ) );", - "float nDotL = saturate( dot( normal, lVector ) );", - "float hDotV = saturate( dot( hVector, viewDirection ) );", - - "#ifdef CLEARCOAT", - - "float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );", - "float visClearCoat = Visibility_Kelemen( hDotV );", - "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );", - "vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;", - - "#endif", - - "#ifdef ANISOTROPY", - - "vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );", - - "#ifdef ANISOTROPYROTATION", - "xyDotH = anisotropicRotationMatrix * xyDotH;", - "#endif", - - "float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );", - - "#else", - - "float d = Distribution_GGX( m2, nDotH );", - - "#endif", - - "float vis = Visibility_Schlick(m2, nDotL, nDotV);", - "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );", - - // Put it all together - "vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;", - "vec3 diff = nDotL * Diffuse_Lambert() * diffuseColor;", - - "#ifdef TRANSLUCENCY", - - "diff *= whiteCompliment( translucencyColor.xyz );", - - "#endif", - - "vec3 shadingResult = spec + diff;", - - "#ifdef CLEARCOAT", - - "shadingResult = mix( shadingResult, specClearCoat, clearCoat );", - - "#endif", - // diffuse - "totalLighting += incidentLight * shadingResult;", - - "#ifdef TRANSLUCENCY", - - "float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );", - - "float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );", - - "totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;", - - "#endif", - - "}", - - "#endif", - - "#if MAX_HEMI_LIGHTS > 0", - - "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", - - "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", - "vec3 lVector = normalize( lDirection.xyz );", - - // diffuse - - "float nDotL = dot( normal, lVector );", - - // based on page 325 of Real-Time Rendering., equation (8.43) - "vec3 hemiColor = ( PI / 2.0 ) * ( ( 1.0 + nDotL ) * hemisphereLightSkyColor[ i ] + ( 1.0 - nDotL ) * hemisphereLightGroundColor[ i ] );", - - "totalLighting += diffuseColor * hemiColor;", - - "}", - - "#endif", - - "#if MAX_AREA_LIGHTS > 0", - - "for( int i = 0; i < MAX_AREA_LIGHTS; i ++ ) {", - - "vec3 lPosition = ( viewMatrix * vec4( areaLightPosition[ i ], 1.0 ) ).xyz;", - //"vec3 lVector = lPosition.xyz + vViewPosition.xyz;", - - "vec3 width = areaLightWidth[ i ];", - "vec3 height = areaLightHeight[ i ];", - "vec3 up = normalize( ( viewMatrix * vec4( height, 0.0 ) ).xyz );", - "vec3 right = normalize( ( viewMatrix * vec4( width, 0.0 ) ).xyz );", - "vec3 pnormal = normalize( cross( right, up ) );", - - "float widthScalar = length( width );", - "float heightScalar = length( height );", - - //project onto plane and calculate direction from center to the projection. - "vec3 projection = projectOnPlane( -vViewPosition.xyz, lPosition, pnormal );", // projection in plane - "vec3 dir = projection - lPosition;", - - //calculate distance from area: - "vec2 diagonal = vec2( dot( dir, right ), dot( dir, up ) );", - "vec2 nearest2D = vec2( clamp( diagonal.x, -widthScalar, widthScalar ), clamp( diagonal.y, -heightScalar, heightScalar ) );", - "vec3 nearestPointInside = lPosition + ( right *nearest2D.x + up * nearest2D.y );", - - "vec3 lVector = ( nearestPointInside + vViewPosition.xyz );", - "float distanceAttenuation = calcLightAttenuation( length( lVector ), areaLightDistance[ i ], areaLightDecayExponent[i] );", - "lVector = normalize( lVector );", - - "vec3 incidentLight = areaLightColor[ i ] * distanceAttenuation * 0.01;", // the 0.01 is the area light intensity scaling. - - "float nDotLDiffuse = saturate( dot( normal, lVector ) );", - - "vec3 diff = Diffuse_Lambert() * diffuseColor * widthScalar * heightScalar;", - - "vec3 viewReflection = reflect( viewDirection.xyz, normal );", - "vec3 reflectionLightPlaneIntersection = linePlaneIntersect( -vViewPosition.xyz, viewReflection, lPosition, pnormal );", - - "float specAngle = dot( viewReflection, pnormal );", - - // && dot( -vViewPosition.xyz - areaLightPosition[ i ], -pnormal ) >= 0.0 - "if ( specAngle < 0.0 ) {", - - "vec3 dirSpec = reflectionLightPlaneIntersection - lPosition;", - "vec2 dirSpec2D = vec2( dot( dirSpec, right ), dot( dirSpec, up ) );", - "vec2 nearestSpec2D = vec2( clamp( dirSpec2D.x, -widthScalar, widthScalar ), clamp( dirSpec2D.y, -heightScalar, heightScalar ) );", - "lVector = normalize( lPosition + ( right *nearestSpec2D.x + up * nearestSpec2D.y ) + vViewPosition.xyz );", - - "} else { ", - - "lVector = vec3( 0 );", - - "}", - - "vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );", - "float nDotH = saturate( dot( normal, hVector ) );", - "float nDotL = saturate( dot( normal, lVector ) );", - "float hDotV = saturate( dot( hVector, viewDirection ) );", - - "#ifdef CLEARCOAT", - - "float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );", - "float visClearCoat = Visibility_Kelemen( hDotV );", - "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );", - "vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;", - - "#endif", - - "#ifdef TRANSLUCENCY", - - "diff *= whiteCompliment( translucencyColor.xyz );", - - "#endif", - - "#ifdef CLEARCOAT", - - "diff = mix( diff, specClearCoat, clearCoat );", - - "#endif", - - - "#ifdef ANISOTROPY", - - "vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );", - - "#ifdef ANISOTROPYROTATION", - "xyDotH = anisotropicRotationMatrix * xyDotH;", - "#endif", - - "float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );", - - "#else", - - "float d = Distribution_GGX( m2, nDotH );", - - "#endif", - - "float vis = Visibility_Schlick(m2, nDotL, nDotV);", - "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );", - - // Put it all together - "vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;", - - "totalLighting += incidentLight * spec;", - "totalLighting += incidentLight * nDotLDiffuse * diff;", - - "#ifdef TRANSLUCENCY", - - "float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );", - - "float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );", - - "totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;", - - "#endif", - - "}", - - "#endif", - - "#ifdef CLEARCOAT", - - "totalLighting += diffuseColor * ( ambientLightColor * ( 1.0 - clearCoat ) );", - - "#else", - - "totalLighting += diffuseColor * ambientLightColor;", - - "#endif", - - "gl_FragColor.xyz += totalLighting;", - - "vec3 emissiveLocal = emissive;", - - "#ifdef USE_EMISSIVEMAP", - - "vec3 emissiveColor = texture2D( emissiveMap, vUv2 ).xyz;", - - "#ifdef GAMMA_INPUT", - - "emissiveColor *= emissiveColor;", - - "#endif", - - "emissiveLocal *= emissiveColor;", - - "#endif", - - "gl_FragColor.xyz += emissiveLocal;", - - "vec3 ambientLocal = ambient;", - - "#ifdef USE_LIGHTMAP", - - "vec3 ambientColor = texture2D( lightMap, vUv2 ).xyz;", - - "#ifdef GAMMA_INPUT", - - "ambientColor *= ambientColor;", - - "#endif", - - "ambientLocal *= ambientColor;", - - "#ifdef CLEARCOAT", - - "ambientLocal *= ( 1.0 - clearCoat );", - - "#endif", - - "#endif", - - "gl_FragColor.xyz += diffuseColor * ambientLocal;", - - ].join("\n"), - - // LIGHTS PHONG - - lights_phong_pars_vertex: [ - - "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", - - "varying vec3 vWorldPosition;", - - "#endif" - - ].join("\n"), - - - lights_phong_vertex: [ - - "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", - - "vWorldPosition = worldPosition.xyz;", - - "#endif" - - ].join("\n"), - - lights_phong_pars_fragment: [ - - "uniform vec3 ambientLightColor;", - - "#if MAX_DIR_LIGHTS > 0", - - "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", - "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", - - "#endif", - - "#if MAX_HEMI_LIGHTS > 0", - - "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", - - "#endif", - - "#if MAX_POINT_LIGHTS > 0", - - "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", - "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", - "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", - "uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];", - - "#endif", - - "#if MAX_SPOT_LIGHTS > 0", - - "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightDecayExponent[ MAX_SPOT_LIGHTS ];", - - "#endif", - - "#if MAX_AREA_LIGHTS > 0", - - "uniform vec3 areaLightColor[ MAX_AREA_LIGHTS ];", - "uniform vec3 areaLightPosition[ MAX_AREA_LIGHTS ];", - "uniform vec3 areaLightWidth[ MAX_AREA_LIGHTS ];", - "uniform vec3 areaLightHeight[ MAX_AREA_LIGHTS ];", - "uniform float areaLightDistance[ MAX_AREA_LIGHTS ];", - "uniform float areaLightDecayExponent[ MAX_AREA_LIGHTS ];", - - "#endif", - - "#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP )", - - "varying vec3 vWorldPosition;", - - "#endif", - - "#ifdef WRAP_AROUND", - - "uniform vec3 wrapRGB;", - - "#endif", - - "varying vec3 vViewPosition;", - "varying vec3 vNormal;" - - ].join("\n"), - - lights_phong_fragment: [ - - "vec3 normal = normalize( vNormal );", - "vec3 viewDirection = normalize( vViewPosition );", - - "#ifdef DOUBLE_SIDED", - - "normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );", - - "#endif", - - "#ifdef USE_NORMALMAP", - - "normal = perturbNormal2Arb( -vViewPosition, normal );", - - "#elif defined( USE_BUMPMAP )", - - "normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );", - - "#endif", - - "#if MAX_POINT_LIGHTS > 0", - - "vec3 pointDiffuse = vec3( 0.0 );", - "vec3 pointSpecular = vec3( 0.0 );", - - "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", - - "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", - "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", - - "float distanceAttenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );", - - "lVector = normalize( lVector );", - - // diffuse - - "float dotProduct = dot( normal, lVector );", - - "float pointDiffuseWeight = max( dotProduct, 0.0 );", - - "pointDiffuse += pointLightColor[ i ] * pointDiffuseWeight * distanceAttenuation;", - - // specular - - "vec3 pointHalfVector = normalize( lVector + viewDirection );", - "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", - "float pointSpecularWeight = specularStrength * pow( max( pointDotNormalHalf, 0.0 ), shininess );", - - // 2.0 => 2.0001 is hack to work around ANGLE bug - - "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", - - "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );", - "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * distanceAttenuation * specularNormalization;", - - "}", - - "#endif", - - "#if MAX_SPOT_LIGHTS > 0", - - "vec3 spotDiffuse = vec3( 0.0 );", - "vec3 spotSpecular = vec3( 0.0 );", - - "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", - - "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", - "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", - - "float distanceAttenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );", - - "lVector = normalize( lVector );", - - "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", - - "if ( spotEffect > spotLightAngleCos[ i ] ) {", - - "spotEffect = pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] );", - - // diffuse - - "float dotProduct = dot( normal, lVector );", - - "#ifdef WRAP_AROUND", - - "float spotDiffuseWeightFull = max( dotProduct, 0.0 );", - "float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", - - "vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", - - "#else", - - "float spotDiffuseWeight = max( dotProduct, 0.0 );", - - "#endif", - - "spotDiffuse += spotLightColor[ i ] * spotDiffuseWeight * distanceAttenuation * spotEffect;", - - // specular - - "vec3 spotHalfVector = normalize( lVector + viewDirection );", - "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", - "float spotSpecularWeight = specularStrength * pow( max( spotDotNormalHalf, 0.0 ), shininess );", - - // 2.0 => 2.0001 is hack to work around ANGLE bug - - "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", - - "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );", - "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * distanceAttenuation * specularNormalization * spotEffect;", - - "}", - - "}", - - "#endif", - - "#if MAX_DIR_LIGHTS > 0", - - "vec3 dirDiffuse = vec3( 0.0 );", - "vec3 dirSpecular = vec3( 0.0 );" , - - "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", - - "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", - "vec3 dirVector = normalize( lDirection.xyz );", - - // diffuse - - "float dotProduct = dot( normal, dirVector );", - - "#ifdef WRAP_AROUND", - - "float dirDiffuseWeightFull = max( dotProduct, 0.0 );", - "float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", - - "vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );", - - "#else", - - "float dirDiffuseWeight = max( dotProduct, 0.0 );", - - "#endif", - - "dirDiffuse += directionalLightColor[ i ] * dirDiffuseWeight;", - - // specular - - "vec3 dirHalfVector = normalize( dirVector + viewDirection );", - "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", - "float dirSpecularWeight = specularStrength * pow( max( dirDotNormalHalf, 0.0 ), shininess );", - - // 2.0 => 2.0001 is hack to work around ANGLE bug - - "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", - - //"dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;", - - "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );", - "dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", - - - "}", - - "#endif", - - "#if MAX_HEMI_LIGHTS > 0", - - "vec3 hemiDiffuse = vec3( 0.0 );", - "vec3 hemiSpecular = vec3( 0.0 );" , - - "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", - - "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", - "vec3 lVector = normalize( lDirection.xyz );", - - // diffuse - - "float dotProduct = dot( normal, lVector );", - "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", - - "vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", - - "hemiDiffuse += hemiColor;", - - // specular (sky light) - - "vec3 hemiHalfVectorSky = normalize( lVector + viewDirection );", - "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", - "float hemiSpecularWeightSky = specularStrength * pow( max( hemiDotNormalHalfSky, 0.0 ), shininess );", - - // specular (ground light) - - "vec3 lVectorGround = -lVector;", - - "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewDirection );", - "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", - "float hemiSpecularWeightGround = specularStrength * pow( max( hemiDotNormalHalfGround, 0.0 ), shininess );", - - "float dotProductGround = dot( normal, lVectorGround );", - - // 2.0 => 2.0001 is hack to work around ANGLE bug - - "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", - - "vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );", - "vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );", - "hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", - - "}", - - "#endif", - - "#if MAX_AREA_LIGHTS > 0", - - "vec3 areaDiffuse = vec3( 0.0 );", - "vec3 areaSpecular = vec3( 0.0 );", - - "for( int i = 0; i < MAX_AREA_LIGHTS; i ++ ) {", - - "vec3 lPosition = ( viewMatrix * vec4( areaLightPosition[ i ], 1.0 ) ).xyz;", - //"vec3 lVector = lPosition.xyz + vViewPosition.xyz;", - - "vec3 width = areaLightWidth[ i ];", - "vec3 height = areaLightHeight[ i ];", - "vec3 up = normalize( ( viewMatrix * vec4( height, 0.0 ) ).xyz );", - "vec3 right = normalize( ( viewMatrix * vec4( width, 0.0 ) ).xyz );", - "vec3 pnormal = normalize( cross( right, up ) );", - - "float widthScalar = length( width );", - "float heightScalar = length( height );", - - //project onto plane and calculate direction from center to the projection. - "vec3 projection = projectOnPlane( -vViewPosition.xyz, lPosition, pnormal );", // projection in plane - "vec3 dir = projection - lPosition;", - - //calculate distance from area: - "vec2 diagonal = vec2( dot( dir, right ), dot( dir, up ) );", - "vec2 nearest2D = vec2( clamp( diagonal.x, -widthScalar, widthScalar ), clamp( diagonal.y, -heightScalar, heightScalar ) );", - "vec3 nearestPointInside = lPosition + ( right *nearest2D.x + up * nearest2D.y );", - - "vec3 lVector = ( nearestPointInside + vViewPosition.xyz );", - "float distanceAttenuation = calcLightAttenuation( length( lVector ), areaLightDistance[ i ], areaLightDecayExponent[i] );", - "lVector = normalize( lVector );", - - "float nDotLDiffuse = saturate( dot( normal, lVector ) );", - - "vec3 viewReflection = reflect( viewDirection.xyz, normal );", - "vec3 reflectionLightPlaneIntersection = linePlaneIntersect( -vViewPosition.xyz, viewReflection, lPosition, pnormal );", - - "float specAngle = dot( viewReflection, pnormal );", - - "if ( specAngle < 0.0 ) {", - - "vec3 dirSpec = reflectionLightPlaneIntersection - lPosition;", - "vec2 dirSpec2D = vec2( dot( dirSpec, right ), dot( dirSpec, up ) );", - "vec2 nearestSpec2D = vec2( clamp( dirSpec2D.x, -widthScalar, widthScalar ), clamp( dirSpec2D.y, -heightScalar, heightScalar ) );", - "lVector = normalize( lPosition + ( right *nearestSpec2D.x + up * nearestSpec2D.y ) + vViewPosition.xyz );", - - "} else { ", - - "lVector = vec3( 0 );", - - "}", - - // diffuse - - "float dotProduct = nDotLDiffuse;", - - "float areaDiffuseWeight = max( dotProduct, 0.0 );", - - "areaDiffuse += areaLightColor[ i ] * areaDiffuseWeight * distanceAttenuation * widthScalar * heightScalar * 0.01;", // the 0.01 is the area light intensity scaling. - - // specular - - "vec3 areaHalfVector = normalize( lVector + viewDirection );", - "float areaDotNormalHalf = max( dot( normal, areaHalfVector ), 0.0 );", - "float areaSpecularWeight = specularStrength * pow( max( areaDotNormalHalf, 0.0 ), shininess );", - - // 2.0 => 2.0001 is hack to work around ANGLE bug - - "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", - - "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, areaHalfVector ), 0.0 ), 5.0 );", - "areaSpecular += schlick * areaLightColor[ i ] * areaSpecularWeight * areaDiffuseWeight * distanceAttenuation * specularNormalization * 0.01;", // the 0.01 is the area light intensity scaling. - - "}", - - "#endif", - - "vec3 totalDiffuse = vec3( 0.0 );", - "vec3 totalSpecular = vec3( 0.0 );", - - "#if MAX_DIR_LIGHTS > 0", - - "totalDiffuse += dirDiffuse;", - "totalSpecular += dirSpecular;", - - "#endif", - - "#if MAX_HEMI_LIGHTS > 0", - - "totalDiffuse += hemiDiffuse;", - "totalSpecular += hemiSpecular;", - - "#endif", - - "#if MAX_POINT_LIGHTS > 0", - - "totalDiffuse += pointDiffuse;", - "totalSpecular += pointSpecular;", - - "#endif", - - "#if MAX_SPOT_LIGHTS > 0", - - "totalDiffuse += spotDiffuse;", - "totalSpecular += spotSpecular;", - - "#endif", - - "#if MAX_AREA_LIGHTS > 0", - - "totalDiffuse += areaDiffuse;", - "totalSpecular += areaSpecular;", - - "#endif", - "vec3 ambientLocal = ambient;", - - "#ifdef USE_LIGHTMAP", - - "vec3 ambientColor = texture2D( lightMap, vUv2 ).xyz;", - - "#ifdef GAMMA_INPUT", - - "ambientColor *= ambientColor;", - - "#endif", - - "ambientLocal *= ambientColor;", - - "#endif", - - "gl_FragColor.xyz = diffuseColor * ( totalDiffuse + ambientLightColor + ambientLocal ) + totalSpecular;", - - "vec3 emissiveLocal = emissive;", - - "#ifdef USE_EMISSIVEMAP", - - "vec3 emissiveColor = texture2D( emissiveMap, vUv2 ).xyz;", - - "#ifdef GAMMA_INPUT", - - "emissiveColor *= emissiveColor;", - - "#endif", - - "emissiveLocal *= emissiveColor;", - - "#endif", - - "gl_FragColor.xyz += emissiveLocal.xyz;", - - ].join("\n"), - - // VERTEX COLORS - - color_pars_fragment: [ - - "#ifdef USE_COLOR", - - "varying vec3 vColor;", - - "#endif" - - ].join("\n"), - - - color_fragment: [ - - "#ifdef USE_COLOR", - - "gl_FragColor = gl_FragColor * vec4( vColor, 1.0 );", - - "#endif" - - ].join("\n"), - - color_pars_vertex: [ - - "#ifdef USE_COLOR", - - "varying vec3 vColor;", - - "#endif" - - ].join("\n"), - - - color_vertex: [ - - "#ifdef USE_COLOR", - - "#ifdef GAMMA_INPUT", - - "vColor = color * color;", - - "#else", - - "vColor = color;", - - "#endif", - - "#endif" - - ].join("\n"), - - // SKINNING - - skinning_pars_vertex: [ - - "#ifdef USE_SKINNING", - - "#ifdef BONE_TEXTURE", - - "uniform sampler2D boneTexture;", - "uniform int boneTextureWidth;", - "uniform int boneTextureHeight;", - - "mat4 getBoneMatrix( const float i ) {", - - "float j = i * 4.0;", - "float x = mod( j, float( boneTextureWidth ) );", - "float y = floor( j / float( boneTextureWidth ) );", - - "float dx = 1.0 / float( boneTextureWidth );", - "float dy = 1.0 / float( boneTextureHeight );", - - "y = dy * ( y + 0.5 );", - - "vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );", - "vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );", - "vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );", - "vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );", - - "mat4 bone = mat4( v1, v2, v3, v4 );", - - "return bone;", - - "}", - - "#else", - - "uniform mat4 boneGlobalMatrices[ MAX_BONES ];", - - "mat4 getBoneMatrix( const float i ) {", - - "mat4 bone = boneGlobalMatrices[ int(i) ];", - "return bone;", - - "}", - - "#endif", - - "#endif" - - ].join("\n"), - - skinbase_vertex: [ - - "#ifdef USE_SKINNING", - - "mat4 boneMatX = getBoneMatrix( skinIndex.x );", - "mat4 boneMatY = getBoneMatrix( skinIndex.y );", - "mat4 boneMatZ = getBoneMatrix( skinIndex.z );", - "mat4 boneMatW = getBoneMatrix( skinIndex.w );", - - "#endif" - - ].join("\n"), - - skinning_vertex: [ - - "#ifdef USE_SKINNING", - - "#ifdef USE_MORPHTARGETS", - - "vec4 skinVertex = vec4( morphed, 1.0 );", - - "#else", - - "vec4 skinVertex = vec4( position, 1.0 );", - - "#endif", - - "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", - "skinned += boneMatY * skinVertex * skinWeight.y;", - "skinned += boneMatZ * skinVertex * skinWeight.z;", - "skinned += boneMatW * skinVertex * skinWeight.w;", - - "#endif" - - ].join("\n"), - - // MORPHING - - morphtarget_pars_vertex: [ - - "#ifdef USE_MORPHTARGETS", - - "#ifndef USE_MORPHNORMALS", - - "uniform float morphTargetInfluences[ 8 ];", - - "#else", - - "uniform float morphTargetInfluences[ 4 ];", - - "#endif", - - "#endif" - - ].join("\n"), - - morphtarget_vertex: [ - - "#ifdef USE_MORPHTARGETS", - - "vec3 morphed = vec3( 0.0 );", - "morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];", - "morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];", - "morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];", - "morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];", - - "#ifndef USE_MORPHNORMALS", - - "morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];", - "morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];", - "morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];", - "morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];", - - "#endif", - - "morphed += position;", - - "#endif" - - ].join("\n"), - - default_vertex : [ - - "vec4 mvPosition;", - - "#ifdef USE_SKINNING", - - "mvPosition = modelViewMatrix * skinned;", - - "#endif", - - "#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )", - - "mvPosition = modelViewMatrix * vec4( morphed, 1.0 );", - - "#endif", - - "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )", - - "mvPosition = modelViewMatrix * vec4( position, 1.0 );", - - "#endif", - - "gl_Position = projectionMatrix * mvPosition;" - - ].join("\n"), - - morphnormal_vertex: [ - - "#ifdef USE_MORPHNORMALS", - - "vec3 morphedNormal = vec3( 0.0 );", - - "morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];", - "morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];", - "morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];", - "morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];", - - "morphedNormal += normal;", - - "#endif" - - ].join("\n"), - - skinnormal_vertex: [ - - "#ifdef USE_SKINNING", - - "mat4 skinMatrix = skinWeight.x * boneMatX;", - "skinMatrix += skinWeight.y * boneMatY;", - - "#ifdef USE_MORPHNORMALS", - - "vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );", - - "#else", - - "vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );", - - "#endif", - - "#endif" - - ].join("\n"), - - defaultnormal_vertex: [ - - "vec3 objectNormal;", - - "#ifdef USE_SKINNING", - - "objectNormal = skinnedNormal.xyz;", - - "#endif", - - "#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )", - - "objectNormal = morphedNormal;", - - "#endif", - - "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )", - - "objectNormal = normal;", - - "#endif", - - "#ifdef FLIP_SIDED", - - "objectNormal = -objectNormal;", - - "#endif", - - "vec3 transformedNormal = normalMatrix * objectNormal;" - - ].join("\n"), - - // SHADOW MAP - - // based on SpiderGL shadow map and Fabien Sanglard's GLSL shadow mapping examples - // http://spidergl.org/example.php?id=6 - // http://fabiensanglard.net/shadowmapping - - shadowmap_pars_fragment: [ - - "#ifdef USE_SHADOWMAP", - - "uniform sampler2D shadowMap[ MAX_SHADOWS ];", - "uniform vec2 shadowMapSize[ MAX_SHADOWS ];", - - "uniform float shadowDarkness[ MAX_SHADOWS ];", - "uniform float shadowBias[ MAX_SHADOWS ];", - - "varying vec4 vShadowCoord[ MAX_SHADOWS ];", - - "float unpackDepth( const vec4 rgba_depth ) {", - - "const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );", - "float depth = dot( rgba_depth, bit_shift );", - "return depth;", - - "}", - - "#endif" - - ].join("\n"), - - shadowmap_fragment: [ - - "#ifdef USE_SHADOWMAP", - - "#ifdef SHADOWMAP_DEBUG", - - "vec3 frustumColors[3];", - "frustumColors[0] = vec3( 1.0, 0.5, 0.0 );", - "frustumColors[1] = vec3( 0.0, 1.0, 0.8 );", - "frustumColors[2] = vec3( 0.0, 0.5, 1.0 );", - - "#endif", - - "#ifdef SHADOWMAP_CASCADE", - - "int inFrustumCount = 0;", - - "#endif", - - "float fDepth;", - "vec3 shadowColor = vec3( 1.0 );", - - "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", - - "vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;", - - // "if ( something && something )" breaks ATI OpenGL shader compiler - // "if ( all( something, something ) )" using this instead - - "bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );", - "bool inFrustum = all( inFrustumVec );", - - // don't shadow pixels outside of light frustum - // use just first frustum (for cascades) - // don't shadow pixels behind far plane of light frustum - - "#ifdef SHADOWMAP_CASCADE", - - "inFrustumCount += int( inFrustum );", - "bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );", - - "#else", - - "bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );", - - "#endif", - - "bool frustumTest = all( frustumTestVec );", - - "if ( frustumTest ) {", - - "shadowCoord.z += shadowBias[ i ];", - - "#if defined( SHADOWMAP_TYPE_PCF )", - - // Percentage-close filtering - // (9 pixel kernel) - // http://fabiensanglard.net/shadowmappingPCF/ - - "float shadow = 0.0;", - - /* - // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL - // must enroll loop manually - - "for ( float y = -1.25; y <= 1.25; y += 1.25 )", - "for ( float x = -1.25; x <= 1.25; x += 1.25 ) {", - - "vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );", - - // doesn't seem to produce any noticeable visual difference compared to simple "texture2D" lookup - //"vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );", - - "float fDepth = unpackDepth( rgbaDepth );", - - "if ( fDepth < shadowCoord.z )", - "shadow += 1.0;", - - "}", - - "shadow /= 9.0;", - - */ - - "const float shadowDelta = 1.0 / 9.0;", - - "float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", - "float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", - - "float dx0 = -1.25 * xPixelOffset;", - "float dy0 = -1.25 * yPixelOffset;", - "float dx1 = 1.25 * xPixelOffset;", - "float dy1 = 1.25 * yPixelOffset;", - - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", - - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", - - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", - - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", - - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", - - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", - - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", - - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", - - "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", - "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", - - "shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", - - "#elif defined( SHADOWMAP_TYPE_PCF_SOFT )", - - // Percentage-close filtering - // (9 pixel kernel) - // http://fabiensanglard.net/shadowmappingPCF/ - - "float shadow = 0.0;", - - "float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", - "float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", - - "float dx0 = -1.0 * xPixelOffset;", - "float dy0 = -1.0 * yPixelOffset;", - "float dx1 = 1.0 * xPixelOffset;", - "float dy1 = 1.0 * yPixelOffset;", - - "mat3 shadowKernel;", - "mat3 depthKernel;", - - "depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", - "depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", - "depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );", - "depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", - "depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", - "depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", - "depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", - "depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", - "depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", - - "vec3 shadowZ = vec3( shadowCoord.z );", - "shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));", - "shadowKernel[0] *= vec3(0.25);", - - "shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));", - "shadowKernel[1] *= vec3(0.25);", - - "shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));", - "shadowKernel[2] *= vec3(0.25);", - - "vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );", - - "shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );", - "shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );", - - "vec4 shadowValues;", - "shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );", - "shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );", - "shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );", - "shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );", - - "shadow = dot( shadowValues, vec4( 1.0 ) );", - - "shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", - - "#else", - - "vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );", - "float fDepth = unpackDepth( rgbaDepth );", - - "if ( fDepth < shadowCoord.z )", - - // spot with multiple shadows is darker - - "shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );", - - // spot with multiple shadows has the same color as single shadow spot - - //"shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );", - - "#endif", - - "}", - - - "#ifdef SHADOWMAP_DEBUG", - - "#ifdef SHADOWMAP_CASCADE", - - "if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];", - - "#else", - - "if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];", - - "#endif", - - "#endif", - - "}", - - "#ifdef GAMMA_OUTPUT", - - "shadowColor *= shadowColor;", - - "#endif", - - "gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;", - - "#endif" - - ].join("\n"), - - shadowmap_pars_vertex: [ - - "#ifdef USE_SHADOWMAP", - - "varying vec4 vShadowCoord[ MAX_SHADOWS ];", - "uniform mat4 shadowMatrix[ MAX_SHADOWS ];", - - "#endif" - - ].join("\n"), - - shadowmap_vertex: [ - - "#ifdef USE_SHADOWMAP", - - "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", - - "vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", - - "}", - - "#endif" - - ].join("\n"), - - // ALPHATEST - - alphatest_fragment: [ - - "#ifdef ALPHATEST", - - "if ( gl_FragColor.a < ALPHATEST ) discard;", - - "#endif" - - ].join("\n"), - - // LINEAR SPACE - - linear_to_gamma_fragment: [ - - "#ifdef GAMMA_OUTPUT", - - "gl_FragColor.xyz = sqrt( gl_FragColor.xyz );", - - "#endif" - - ].join("\n") - - -}; -/** - * Uniform Utilities - */ - -THREE.UniformsUtils = { - - merge: function ( uniforms ) { - - var u, p, tmp, merged = {}; - - for ( u = 0; u < uniforms.length; u ++ ) { - - tmp = this.clone( uniforms[ u ] ); - - for ( p in tmp ) { - - merged[ p ] = tmp[ p ]; - - } - - } - - return merged; - - }, - - clone: function ( uniforms_src ) { - - var u, p, parameter, parameter_src, uniforms_dst = {}; - - for ( u in uniforms_src ) { - - uniforms_dst[ u ] = {}; - - for ( p in uniforms_src[ u ] ) { - - parameter_src = uniforms_src[ u ][ p ]; - - if ( parameter_src instanceof THREE.Color || - parameter_src instanceof THREE.Vector2 || - parameter_src instanceof THREE.Vector3 || - parameter_src instanceof THREE.Vector4 || - parameter_src instanceof THREE.Matrix4 || - parameter_src instanceof THREE.Texture ) { - - uniforms_dst[ u ][ p ] = parameter_src.clone(); - - } else if ( parameter_src instanceof Array ) { - - uniforms_dst[ u ][ p ] = parameter_src.slice(); - - } else { - - uniforms_dst[ u ][ p ] = parameter_src; - - } - - } - - } - - return uniforms_dst; - - } - -}; -/** - * Uniforms library for shared webgl shaders - */ - -THREE.UniformsLib = { - - common: { - - "diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, - "opacity" : { type: "f", value: 1.0 }, - - "map" : { type: "t", value: null }, - "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - "gainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, - - "lightMap" : { type: "t", value: null }, - "emissiveMap" : { type: "t", value: null }, - "envMap" : { type: "t", value: null }, - "envEncoding" : { type: "i", value: 0 }, - "diffuseEnvMap" : { type: "t", value: null }, - "diffuseEnvEncoding" : { type: "i", value: 0 }, - "flipEnvMap" : { type: "f", value: -1 }, - "useRefract" : { type: "i", value: 0 }, - "reflectivity" : { type: "f", value: 1.0 }, - "refractionRatio" : { type: "f", value: 0.98 }, - "combine" : { type: "i", value: 0 }, - - "morphTargetInfluences" : { type: "f", value: 0 } - - }, - - specularmap: { - - "specularMap" : { type: "t", value: null }, - "specularOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - "specularGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, - - }, - - bumpmap: { - - "bumpMap" : { type: "t", value: null }, - "bumpScale" : { type: "f", value: 1 }, // used instead of 'bumpGainBrightness' - "bumpOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) } - - }, - - opacitymap: { - - "opacityMap" : { type: "t", value: null }, - "opacityOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - "opacityGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, - - }, - - normalmap: { - - "normalMap" : { type: "t", value: null }, - "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }, // used instead of 'normalGainBrightness' - "normalOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) } - - }, - - fog : { - - "fogDensity" : { type: "f", value: 0.00025 }, - "fogNear" : { type: "f", value: 1 }, - "fogFar" : { type: "f", value: 2000 }, - "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } - - }, - - lights: { - - "ambientLightColor" : { type: "fv", value: [] }, - - "directionalLightDirection" : { type: "fv", value: [] }, - "directionalLightColor" : { type: "fv", value: [] }, - - "hemisphereLightDirection" : { type: "fv", value: [] }, - "hemisphereLightSkyColor" : { type: "fv", value: [] }, - "hemisphereLightGroundColor" : { type: "fv", value: [] }, - - "pointLightColor" : { type: "fv", value: [] }, - "pointLightPosition" : { type: "fv", value: [] }, - "pointLightDistance" : { type: "fv1", value: [] }, - "pointLightDecayExponent" : { type: "fv1", value: [] }, - - "spotLightColor" : { type: "fv", value: [] }, - "spotLightPosition" : { type: "fv", value: [] }, - "spotLightDirection" : { type: "fv", value: [] }, - "spotLightDistance" : { type: "fv1", value: [] }, - "spotLightDecayExponent" : { type: "fv1", value: [] }, - "spotLightAngleCos" : { type: "fv1", value: [] }, - "spotLightExponent" : { type: "fv1", value: [] }, - - "areaLightColor" : { type: "fv", value: [] }, - "areaLightPosition" : { type: "fv", value: [] }, - "areaLightDistance" : { type: "fv1", value: [] }, - "areaLightDecayExponent" : { type: "fv1", value: [] }, - "areaLightWidth" : { type: "fv", value: [] }, - "areaLightHeight" : { type: "fv", value: [] } - - }, - - particle: { - - "psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, - "opacity" : { type: "f", value: 1.0 }, - "size" : { type: "f", value: 1.0 }, - "scale" : { type: "f", value: 1.0 }, - "map" : { type: "t", value: null }, - - "fogDensity" : { type: "f", value: 0.00025 }, - "fogNear" : { type: "f", value: 1 }, - "fogFar" : { type: "f", value: 2000 }, - "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } - - }, - - shadowmap: { - - "shadowMap": { type: "tv", value: [] }, - "shadowMapSize": { type: "v2v", value: [] }, - - "shadowBias" : { type: "fv1", value: [] }, - "shadowDarkness": { type: "fv1", value: [] }, - - "shadowMatrix" : { type: "m4v", value: [] } - - } - -}; -/** - * Webgl Shader Library for three.js - * - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author bhouston / http://clara.io/ - */ - - -THREE.ShaderLib = { - - - 'physical': { - - uniforms: THREE.UniformsUtils.merge( [ - - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "bumpmap" ], - THREE.UniformsLib[ "normalmap" ], - //THREE.UniformsLib[ "roughnessmap" ], TODO: Implement me! - //THREE.UniformsLib[ "metallicmap" ], TODO: Implement me! - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], - THREE.UniformsLib[ "shadowmap" ], - THREE.UniformsLib[ "opacitymap" ], - THREE.UniformsLib[ "specularmap" ], - - { - "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, - "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, - "specular" : { type: "c", value: new THREE.Color( 0xFFFFFF ) }, - "falloffColor" : { type: "c", value: new THREE.Color( 0xFFFFFF ) }, - "falloffMap" : { type: "t", value: null }, - "falloffBlendParams" : { type: "v4", value: new THREE.Vector4( 1, 0, 0, 1 ) }, - - "clearCoat": { type: "f", value: 0.0 }, - "clearCoatRoughness": { type: "f", value: 0.25 }, - - "roughness": { type: "f", value: 0.5 }, - "roughnessMap" : { type: "t", value: null }, - "roughnessOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - "roughnessGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, - - "metallic": { type: "f", value: 0.5 }, - "metallicMap" : { type: "t", value: null }, - "metallicOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - "metallicGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, - - "anisotropy": { type: "f", value: 0.0 }, - "anisotropyMap" : { type: "t", value: null }, - "anisotropyOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - "anisotropyGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, - - "anisotropyRotation": { type: "f", value: 0.0 }, - "anisotropyRotationMap" : { type: "t", value: null }, - "anisotropyRotationOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, - "anisotropyRotationGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, - - "translucency" : { type: "c", value: new THREE.Color( 0x000000 ) }, - "translucencyMap" : { type: "t", value: null }, - "translucencyNormalAlpha": { type: "f", value: 0.75 }, - "translucencyNormalPower": { type: "f", value: 2.0 }, - "translucencyViewAlpha": { type: "f", value: 0.75 }, - "translucencyViewPower": { type: "f", value: 2.0 }, - - } - - ] ), - - vertexShader: [ - - "attribute vec4 tangent;", - - "#define PHONG", - "#define PHYSICAL", - - "varying vec3 vViewPosition;", - "varying vec3 vTangent;", - "varying vec3 vBinormal;", - "varying vec3 vNormal;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "map_pars_vertex" ], - THREE.ShaderChunk[ "normalmap_pars_vertex" ], - THREE.ShaderChunk[ "roughnessmap_pars_vertex" ], - THREE.ShaderChunk[ "specularmap_pars_vertex" ], - THREE.ShaderChunk[ "opacitymap_pars_vertex" ], - THREE.ShaderChunk[ "anisotropymap_pars_vertex" ], - THREE.ShaderChunk[ "anisotropyrotationmap_pars_vertex" ], - THREE.ShaderChunk[ "metallicmap_pars_vertex" ], - THREE.ShaderChunk[ "translucencymap_pars_vertex" ], - THREE.ShaderChunk[ "bumpmap_pars_vertex" ], - THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "lights_physical_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "map_vertex" ], - THREE.ShaderChunk[ "normalmap_vertex" ], - THREE.ShaderChunk[ "roughnessmap_vertex" ], - THREE.ShaderChunk[ "opacitymap_vertex" ], - THREE.ShaderChunk[ "specularmap_vertex" ], - THREE.ShaderChunk[ "anisotropymap_vertex" ], - THREE.ShaderChunk[ "anisotropyrotationmap_vertex" ], - THREE.ShaderChunk[ "metallicmap_vertex" ], - THREE.ShaderChunk[ "translucencymap_vertex" ], - THREE.ShaderChunk[ "bumpmap_vertex" ], - THREE.ShaderChunk[ "lightmap_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], - - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], - - "vNormal = normalize( transformedNormal );", - - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - - "vViewPosition = -mvPosition.xyz;", - - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "lights_physical_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "#ifdef TEXTURE_CUBE_LOD_EXT", - "#extension GL_EXT_shader_texture_lod : enable", - "#endif", - "#define PHYSICAL", - "uniform vec3 diffuse;", - "uniform float opacity;", - - "uniform vec3 ambient;", - "uniform vec3 emissive;", - "uniform vec3 falloffColor;", - "uniform vec4 falloffBlendParams;", - "uniform vec3 specular;", - "uniform float roughness;", - "uniform float metallic;", - "uniform float clearCoat;", - "uniform float clearCoatRoughness;", - - "uniform vec3 translucency;", - "uniform float translucencyNormalAlpha;", - "uniform float translucencyNormalPower;", - "uniform float translucencyViewPower;", - "uniform float translucencyViewAlpha;", - - "uniform float anisotropy;", - "uniform float anisotropyRotation;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "falloffmap_pars_fragment" ], - THREE.ShaderChunk[ "opacitymap_pars_fragment" ], - THREE.ShaderChunk[ "translucencymap_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "diffuseenvmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "lights_physical_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "bumpmap_pars_fragment" ], - THREE.ShaderChunk[ "normalmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], - THREE.ShaderChunk[ "anisotropymap_pars_fragment" ], - THREE.ShaderChunk[ "anisotropyrotationmap_pars_fragment" ], - THREE.ShaderChunk[ "metallicmap_pars_fragment" ], - THREE.ShaderChunk[ "roughnessmap_pars_fragment" ], - THREE.ShaderChunk[ "reflectivitymap_pars_fragment" ], - THREE.ShaderChunk[ "lightattenuation_func_fragment" ], - - "void main() {", - - "gl_FragColor = vec4( vec3 ( 0.0 ), opacity );", - "vec3 diffuseColor = diffuse;", - "vec3 translucencyColor = translucency;", - "vec3 normal = normalize( vNormal );", - "vec3 viewDirection = normalize( vViewPosition );", - - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "opacitymap_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], - THREE.ShaderChunk[ "anisotropymap_fragment" ], - THREE.ShaderChunk[ "anisotropyrotationmap_fragment" ], - THREE.ShaderChunk[ "roughnessmap_fragment" ], - THREE.ShaderChunk[ "metallicmap_fragment" ], - THREE.ShaderChunk[ "translucencymap_fragment" ], - THREE.ShaderChunk[ "reflectivitymap_fragment" ], - - THREE.ShaderChunk[ "lights_physical_fragment" ], - - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], - - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - - THREE.ShaderChunk[ "fog_fragment" ], - - "gl_FragColor.xyz *= gl_FragColor.w;", // premultipled, must be used with CustomBlender, OneFactor, OneMinusSrcAlphaFactor, AddEquation. - - "}" - - ].join("\n") - - }, - - 'basic': { - - uniforms: THREE.UniformsUtils.merge( [ - - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "shadowmap" ] - - ] ), - - vertexShader: [ - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "map_pars_vertex" ], - THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "map_vertex" ], - THREE.ShaderChunk[ "lightmap_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], - - "#ifdef USE_ENVMAP", - - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], - - "#endif", - - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform vec3 diffuse;", - "uniform float opacity;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], - - "void main() {", - - "gl_FragColor = vec4( diffuse, opacity );", - - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], - - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - - THREE.ShaderChunk[ "fog_fragment" ], - - "}" - - ].join("\n") - - }, - - 'lambert': { - - uniforms: THREE.UniformsUtils.merge( [ - - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], - THREE.UniformsLib[ "shadowmap" ], - - { - "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, - "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, - "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } - } - - ] ), - - vertexShader: [ - - "#define LAMBERT", - - "varying vec3 vLightFront;", - - "#ifdef DOUBLE_SIDED", - - "varying vec3 vLightBack;", - - "#endif", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "map_pars_vertex" ], - THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "lights_lambert_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - THREE.ShaderChunk[ "lightattenuation_func_fragment" ], - - "void main() {", - - THREE.ShaderChunk[ "map_vertex" ], - THREE.ShaderChunk[ "lightmap_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], - - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], - - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "lights_lambert_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform float opacity;", - - "varying vec3 vLightFront;", - - "#ifdef DOUBLE_SIDED", - - "varying vec3 vLightBack;", - - "#endif", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], - - "void main() {", - - "gl_FragColor = vec4( vec3 ( 1.0 ), opacity );", - - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], - - "#ifdef DOUBLE_SIDED", - - //"float isFront = float( gl_FrontFacing );", - //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", - - "if ( gl_FrontFacing )", - "gl_FragColor.xyz *= vLightFront;", - "else", - "gl_FragColor.xyz *= vLightBack;", - - "#else", - - "gl_FragColor.xyz *= vLightFront;", - - "#endif", - - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], - - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - - THREE.ShaderChunk[ "fog_fragment" ], - - "}" - - ].join("\n") - - }, - - 'phong': { - - uniforms: THREE.UniformsUtils.merge( [ - - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "bumpmap" ], - THREE.UniformsLib[ "normalmap" ], - THREE.UniformsLib[ "specularmap" ], - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], - THREE.UniformsLib[ "shadowmap" ], - THREE.UniformsLib[ "opacitymap" ], - - { - "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, - "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, - "specular" : { type: "c", value: new THREE.Color( 0x111111 ) }, - "shininess": { type: "f", value: 30 }, - "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } - } - - ] ), - - vertexShader: [ - - "#define PHONG", - - "varying vec3 vViewPosition;", - "varying vec3 vNormal;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "map_pars_vertex" ], - THREE.ShaderChunk[ "normalmap_pars_vertex" ], - THREE.ShaderChunk[ "bumpmap_pars_vertex" ], - THREE.ShaderChunk[ "specularmap_pars_vertex" ], - THREE.ShaderChunk[ "opacitymap_pars_vertex" ], - THREE.ShaderChunk[ "lightmap_pars_vertex" ], - THREE.ShaderChunk[ "lights_phong_pars_vertex" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "map_vertex" ], - THREE.ShaderChunk[ "normalmap_vertex" ], - THREE.ShaderChunk[ "bumpmap_vertex" ], - THREE.ShaderChunk[ "opacitymap_vertex" ], - THREE.ShaderChunk[ "specularmap_vertex" ], - THREE.ShaderChunk[ "lightmap_vertex" ], - THREE.ShaderChunk[ "color_vertex" ], - - THREE.ShaderChunk[ "morphnormal_vertex" ], - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - THREE.ShaderChunk[ "defaultnormal_vertex" ], - - "vNormal = normalize( transformedNormal );", - - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - - "vViewPosition = -mvPosition.xyz;", - - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "lights_phong_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "#define PHONG", - - "uniform vec3 diffuse;", - "uniform float opacity;", - - "uniform vec3 ambient;", - "uniform vec3 emissive;", - "uniform vec3 specular;", - "uniform float shininess;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_pars_fragment" ], - THREE.ShaderChunk[ "opacitymap_pars_fragment" ], - THREE.ShaderChunk[ "lightmap_pars_fragment" ], - THREE.ShaderChunk[ "envmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "lights_phong_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "bumpmap_pars_fragment" ], - THREE.ShaderChunk[ "normalmap_pars_fragment" ], - THREE.ShaderChunk[ "specularmap_pars_fragment" ], - THREE.ShaderChunk[ "lightattenuation_func_fragment" ], - - "void main() {", - - "gl_FragColor = vec4( vec3 ( 1.0 ), opacity );", - "vec3 diffuseColor = diffuse;", - - THREE.ShaderChunk[ "map_fragment" ], - THREE.ShaderChunk[ "opacitymap_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "specularmap_fragment" ], - - THREE.ShaderChunk[ "lights_phong_fragment" ], - - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], - - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - - THREE.ShaderChunk[ "fog_fragment" ], - - "}" - - ].join("\n") - - }, - - 'particle_basic': { - - uniforms: THREE.UniformsUtils.merge( [ - - THREE.UniformsLib[ "particle" ], - THREE.UniformsLib[ "shadowmap" ] - - ] ), - - vertexShader: [ - - "uniform float size;", - "uniform float scale;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "color_vertex" ], - - "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", - - "#ifdef USE_SIZEATTENUATION", - "gl_PointSize = size * ( scale / length( mvPosition.xyz ) );", - "#else", - "gl_PointSize = size;", - "#endif", - - "gl_Position = projectionMatrix * mvPosition;", - - THREE.ShaderChunk[ "worldpos_vertex" ], - THREE.ShaderChunk[ "shadowmap_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform vec3 psColor;", - "uniform float opacity;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "map_particle_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - - "void main() {", - - "gl_FragColor = vec4( psColor, opacity );", - - THREE.ShaderChunk[ "map_particle_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], - THREE.ShaderChunk[ "fog_fragment" ], - - "}" - - ].join("\n") - - }, - - 'dashed': { - - uniforms: THREE.UniformsUtils.merge( [ - - THREE.UniformsLib[ "common" ], - THREE.UniformsLib[ "fog" ], - - { - "scale": { type: "f", value: 1 }, - "dashSize": { type: "f", value: 1 }, - "totalSize": { type: "f", value: 2 } - } - - ] ), - - vertexShader: [ - - "uniform float scale;", - "attribute float lineDistance;", - - "varying float vLineDistance;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "color_vertex" ], - - "vLineDistance = scale * lineDistance;", - - "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", - "gl_Position = projectionMatrix * mvPosition;", - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform vec3 diffuse;", - "uniform float opacity;", - - "uniform float dashSize;", - "uniform float totalSize;", - - "varying float vLineDistance;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "color_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - - "void main() {", - - "if ( mod( vLineDistance, totalSize ) > dashSize ) {", - - "discard;", - - "}", - - "gl_FragColor = vec4( diffuse, opacity );", - - THREE.ShaderChunk[ "color_fragment" ], - THREE.ShaderChunk[ "fog_fragment" ], - - "}" - - ].join("\n") - - }, - - 'depth': { - - uniforms: { - - "mNear": { type: "f", value: 1.0 }, - "mFar" : { type: "f", value: 2000.0 }, - "opacity" : { type: "f", value: 1.0 } - - }, - - vertexShader: [ - - "void main() {", - - "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform float mNear;", - "uniform float mFar;", - "uniform float opacity;", - - "void main() {", - - "float depth = gl_FragCoord.z / gl_FragCoord.w;", - "float color = clamp( ( depth - mNear ) / ( mFar - mNear ), 0.0, 1.0 );", - "gl_FragColor = vec4( vec3( color ), opacity );", - - "}" - - ].join("\n") - - }, - - 'normal': { - - uniforms: { - - "opacity" : { type: "f", value: 1.0 } - - }, - - vertexShader: [ - - "varying vec3 vNormal;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - - "void main() {", - - "vNormal = normalize( normalMatrix * normal );", - - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform float opacity;", - "varying vec3 vNormal;", - - "void main() {", - - "gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );", - - "}" - - ].join("\n") - - }, - - /* ------------------------------------------------------------------------- - // Normal map shader - // - Blinn-Phong - // - normal + diffuse + specular + AO + displacement + reflection + shadow maps - // - point and directional lights (use with "lights: true" material option) - ------------------------------------------------------------------------- */ - - 'normalmap' : { - - uniforms: THREE.UniformsUtils.merge( [ - - THREE.UniformsLib[ "fog" ], - THREE.UniformsLib[ "lights" ], - THREE.UniformsLib[ "shadowmap" ], - - { - - "enableAO" : { type: "i", value: 0 }, - "enableDiffuse" : { type: "i", value: 0 }, - "enableSpecular" : { type: "i", value: 0 }, - "enableReflection": { type: "i", value: 0 }, - "enableDisplacement": { type: "i", value: 0 }, - - "tDisplacement": { type: "t", value: null }, // must go first as this is vertex texture - "tDiffuse" : { type: "t", value: null }, - "tCube" : { type: "t", value: null }, - "tNormal" : { type: "t", value: null }, - "tSpecular" : { type: "t", value: null }, - "tAO" : { type: "t", value: null }, - - "uNormalScale": { type: "v2", value: new THREE.Vector2( 1, 1 ) }, - - "uDisplacementBias": { type: "f", value: 0.0 }, - "uDisplacementScale": { type: "f", value: 1.0 }, - - "diffuse": { type: "c", value: new THREE.Color( 0xffffff ) }, - "specular": { type: "c", value: new THREE.Color( 0x111111 ) }, - "ambient": { type: "c", value: new THREE.Color( 0xffffff ) }, - "shininess": { type: "f", value: 30 }, - "opacity": { type: "f", value: 1 }, - - "useRefract": { type: "i", value: 0 }, - "refractionRatio": { type: "f", value: 0.98 }, - "reflectivity": { type: "f", value: 0.5 }, - - "uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) }, - "uRepeat" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }, - - "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } - - } - - ] ), - - fragmentShader: [ - - "uniform vec3 ambient;", - "uniform vec3 diffuse;", - "uniform vec3 specular;", - "uniform float shininess;", - "uniform float opacity;", - - "uniform bool enableDiffuse;", - "uniform bool enableSpecular;", - "uniform bool enableAO;", - "uniform bool enableReflection;", - - "uniform sampler2D tDiffuse;", - "uniform sampler2D tNormal;", - "uniform sampler2D tSpecular;", - "uniform sampler2D tAO;", - - "uniform samplerCube tCube;", - - "uniform vec2 uNormalScale;", - - "uniform bool useRefract;", - "uniform float refractionRatio;", - "uniform float reflectivity;", - - "varying vec3 vTangent;", - "varying vec3 vBinormal;", - "varying vec3 vNormal;", - "varying vec2 vUv;", - - "uniform vec3 ambientLightColor;", - - "#if MAX_DIR_LIGHTS > 0", - - "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", - "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", - - "#endif", - - "#if MAX_HEMI_LIGHTS > 0", - - "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", - "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", - - "#endif", - - "#if MAX_POINT_LIGHTS > 0", - - "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", - "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", - "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", - - "#endif", - - "#if MAX_SPOT_LIGHTS > 0", - - "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", - "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", - "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", - - "#endif", - - "#ifdef WRAP_AROUND", - - "uniform vec3 wrapRGB;", - - "#endif", - - "varying vec3 vWorldPosition;", - "varying vec3 vViewPosition;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "shadowmap_pars_fragment" ], - THREE.ShaderChunk[ "fog_pars_fragment" ], - - "void main() {", - - "gl_FragColor = vec4( vec3( 1.0 ), opacity );", - - "vec3 specularTex = vec3( 1.0 );", - - "vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;", - "normalTex.xy *= uNormalScale;", - "normalTex = normalize( normalTex );", - - "if( enableDiffuse ) {", - - "#ifdef GAMMA_INPUT", - - "vec4 texelColor = texture2D( tDiffuse, vUv );", - "texelColor.xyz *= texelColor.xyz;", - - "gl_FragColor = gl_FragColor * texelColor;", - - "#else", - - "gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );", - - "#endif", - - "}", - - "if( enableAO ) {", - - "#ifdef GAMMA_INPUT", - - "vec4 aoColor = texture2D( tAO, vUv );", - "aoColor.xyz *= aoColor.xyz;", - - "gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;", - - "#else", - - "gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;", - - "#endif", - - "}", - - "if( enableSpecular )", - "specularTex = texture2D( tSpecular, vUv ).xyz;", - - "mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );", - "vec3 finalNormal = tsb * normalTex;", - - "#ifdef FLIP_SIDED", - - "finalNormal = -finalNormal;", - - "#endif", - - "vec3 normal = normalize( finalNormal );", - "vec3 viewDirection = normalize( vViewPosition );", - - // point lights - - "#if MAX_POINT_LIGHTS > 0", - - "vec3 pointDiffuse = vec3( 0.0 );", - "vec3 pointSpecular = vec3( 0.0 );", - - "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", - - "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", - "vec3 pointVector = lPosition.xyz + vViewPosition.xyz;", - - "float pointDistance = 1.0;", - "if ( pointLightDistance[ i ] > 0.0 )", - "pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );", - - "pointVector = normalize( pointVector );", - - // diffuse - - "#ifdef WRAP_AROUND", - - "float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );", - "float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );", - - "vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );", - - "#else", - - "float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );", - - "#endif", - - "pointDiffuse += pointDistance * pointLightColor[ i ] * diffuse * pointDiffuseWeight;", - - // specular - - "vec3 pointHalfVector = normalize( pointVector + viewDirection );", - "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", - "float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );", - - // 2.0 => 2.0001 is hack to work around ANGLE bug - - "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", - - "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );", - "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;", - - "}", - - "#endif", - - // spot lights - - "#if MAX_SPOT_LIGHTS > 0", - - "vec3 spotDiffuse = vec3( 0.0 );", - "vec3 spotSpecular = vec3( 0.0 );", - - "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", - - "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", - "vec3 spotVector = lPosition.xyz + vViewPosition.xyz;", - - "float spotDistance = 1.0;", - "if ( spotLightDistance[ i ] > 0.0 )", - "spotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );", - - "spotVector = normalize( spotVector );", - - "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", - - "if ( spotEffect > spotLightAngleCos[ i ] ) {", - - "spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", - - // diffuse - - "#ifdef WRAP_AROUND", - - "float spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );", - "float spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );", - - "vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", - - "#else", - - "float spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );", - - "#endif", - - "spotDiffuse += spotDistance * spotLightColor[ i ] * diffuse * spotDiffuseWeight * spotEffect;", - - // specular - - "vec3 spotHalfVector = normalize( spotVector + viewDirection );", - "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", - "float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, shininess ), 0.0 );", - - // 2.0 => 2.0001 is hack to work around ANGLE bug - - "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", - - "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );", - "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;", - - "}", - - "}", - - "#endif", - - // directional lights - - "#if MAX_DIR_LIGHTS > 0", - - "vec3 dirDiffuse = vec3( 0.0 );", - "vec3 dirSpecular = vec3( 0.0 );", - - "for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {", - - "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", - "vec3 dirVector = normalize( lDirection.xyz );", - - // diffuse - - "#ifdef WRAP_AROUND", - - "float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );", - "float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );", - - "vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );", - - "#else", - - "float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );", - - "#endif", - - "dirDiffuse += directionalLightColor[ i ] * diffuse * dirDiffuseWeight;", - - // specular - - "vec3 dirHalfVector = normalize( dirVector + viewDirection );", - "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", - "float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, shininess ), 0.0 );", - - // 2.0 => 2.0001 is hack to work around ANGLE bug - - "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", - - "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );", - "dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", - - "}", - - "#endif", - - // hemisphere lights - - "#if MAX_HEMI_LIGHTS > 0", - - "vec3 hemiDiffuse = vec3( 0.0 );", - "vec3 hemiSpecular = vec3( 0.0 );" , - - "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", - - "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", - "vec3 lVector = normalize( lDirection.xyz );", - - // diffuse - - "float dotProduct = dot( normal, lVector );", - "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", - - "vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", - - "hemiDiffuse += diffuse * hemiColor;", - - // specular (sky light) - - - "vec3 hemiHalfVectorSky = normalize( lVector + viewDirection );", - "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", - "float hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", - - // specular (ground light) - - "vec3 lVectorGround = -lVector;", - - "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewDirection );", - "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", - "float hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", - - "float dotProductGround = dot( normal, lVectorGround );", - - // 2.0 => 2.0001 is hack to work around ANGLE bug - - "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", - - "vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );", - "vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );", - "hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", - - "}", - - "#endif", - - // all lights contribution summation - - "vec3 totalDiffuse = vec3( 0.0 );", - "vec3 totalSpecular = vec3( 0.0 );", - - "#if MAX_DIR_LIGHTS > 0", - - "totalDiffuse += dirDiffuse;", - "totalSpecular += dirSpecular;", - - "#endif", - - "#if MAX_HEMI_LIGHTS > 0", - - "totalDiffuse += hemiDiffuse;", - "totalSpecular += hemiSpecular;", - - "#endif", - - "#if MAX_POINT_LIGHTS > 0", - - "totalDiffuse += pointDiffuse;", - "totalSpecular += pointSpecular;", - - "#endif", - - "#if MAX_SPOT_LIGHTS > 0", - - "totalDiffuse += spotDiffuse;", - "totalSpecular += spotSpecular;", - - "#endif", - - "#ifdef METAL", - - "gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient + totalSpecular );", - - "#else", - - "gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient ) + totalSpecular;", - - "#endif", - - "if ( enableReflection ) {", - - "vec3 vReflect;", - "vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", - - "if ( useRefract ) {", - - "vReflect = refract( cameraToVertex, normal, refractionRatio );", - - "} else {", - - "vReflect = reflect( cameraToVertex, normal );", - - "}", - - "vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );", - - "#ifdef GAMMA_INPUT", - - "cubeColor.xyz *= cubeColor.xyz;", - - "#endif", - - "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * reflectivity );", - - "}", - - THREE.ShaderChunk[ "shadowmap_fragment" ], - THREE.ShaderChunk[ "linear_to_gamma_fragment" ], - THREE.ShaderChunk[ "fog_fragment" ], - - "}" - - ].join("\n"), - - vertexShader: [ - - "attribute vec4 tangent;", - - "uniform vec2 uOffset;", - "uniform vec2 uRepeat;", - - "uniform bool enableDisplacement;", - - "#ifdef VERTEX_TEXTURES", - - "uniform sampler2D tDisplacement;", - "uniform float uDisplacementScale;", - "uniform float uDisplacementBias;", - - "#endif", - - "varying vec3 vTangent;", - "varying vec3 vBinormal;", - "varying vec3 vNormal;", - "varying vec2 vUv;", - - "varying vec3 vWorldPosition;", - "varying vec3 vViewPosition;", - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - THREE.ShaderChunk[ "shadowmap_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "skinnormal_vertex" ], - - // normal, tangent and binormal vectors - - "#ifdef USE_SKINNING", - - "vNormal = normalize( normalMatrix * skinnedNormal.xyz );", - - "vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );", - "vTangent = normalize( normalMatrix * skinnedTangent.xyz );", - - "#else", - - "vNormal = normalize( normalMatrix * normal );", - "vTangent = normalize( normalMatrix * tangent.xyz );", - - "#endif", - - "vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );", - - "vUv = uv * uRepeat + uOffset;", - - // displacement mapping - - "vec3 displacedPosition;", - - "#ifdef VERTEX_TEXTURES", - - "if ( enableDisplacement ) {", - - "vec3 dv = texture2D( tDisplacement, uv ).xyz;", - "float df = uDisplacementScale * dv.x + uDisplacementBias;", - "displacedPosition = position + normalize( normal ) * df;", - - "} else {", - - "#ifdef USE_SKINNING", - - "vec4 skinVertex = vec4( position, 1.0 );", - - "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", - "skinned += boneMatY * skinVertex * skinWeight.y;", - - "displacedPosition = skinned.xyz;", - - "#else", - - "displacedPosition = position;", - - "#endif", - - "}", - - "#else", - - "#ifdef USE_SKINNING", - - "vec4 skinVertex = vec4( position, 1.0 );", - - "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", - "skinned += boneMatY * skinVertex * skinWeight.y;", - - "displacedPosition = skinned.xyz;", - - "#else", - - "displacedPosition = position;", - - "#endif", - - "#endif", - - // - - "vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );", - "vec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );", - - "gl_Position = projectionMatrix * mvPosition;", - - // - - "vWorldPosition = worldPosition.xyz;", - "vViewPosition = -mvPosition.xyz;", - - // shadows - - "#ifdef USE_SHADOWMAP", - - "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", - - "vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", - - "}", - - "#endif", - - "}" - - ].join("\n") - - }, - - /* ------------------------------------------------------------------------- - // Cube map shader - ------------------------------------------------------------------------- */ - - 'cube': { - - uniforms: { "tCube": { type: "t", value: null }, - "tFlip": { type: "f", value: -1 }, - "tEncoding": { type: "i", value: 0 }, - "blurring": { type: "f", value: 0 } - }, - - vertexShader: [ - - "varying vec3 vWorldPosition;", - - "void main() {", - - "vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", - "vWorldPosition = worldPosition.xyz;", - - "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", - - "}" - - ].join("\n"), - - fragmentShader: [ - - "#ifdef TEXTURE_CUBE_LOD_EXT", - "#extension GL_EXT_shader_texture_lod : enable", - "#endif", - - THREE.ShaderChunk[ "common" ], - - "uniform samplerCube tCube;", - "uniform float tFlip;", - "uniform int tEncoding;", - "uniform float blurring;", - - "varying vec3 vWorldPosition;", - - "void main() {", - - "vec3 queryVector = vec3( tFlip * vWorldPosition.x, vWorldPosition.yz );", - - "#if defined( TEXTURE_CUBE_LOD_EXT )", - - "vec4 color = textureCubeLodEXT( tCube, queryVector, blurring );", - - "#else", - - "vec4 color = textureCube( tCube, queryVector );", - - "#endif", - - "color = texelDecode( color, tEncoding );", - - "#ifdef GAMMA_OUTPUT", - - "color.xyz = sqrt( color.xyz );", - - "#endif", - - "gl_FragColor = color;", - - "}" - - ].join("\n") - - }, - - // Depth encoding into RGBA texture - // based on SpiderGL shadow map example - // http://spidergl.org/example.php?id=6 - // originally from - // http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD - // see also here: - // http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ - - 'depthRGBA': { - - uniforms: {}, - - vertexShader: [ - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - - "void main() {", - - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - - "}" - - ].join("\n"), - - fragmentShader: [ - - "vec4 pack_depth( const float depth ) {", - - " const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", - " const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", - " vec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );", // " vec4 res = fract( depth * bit_shift );", - " res -= res.xxyz * bit_mask;", - " return res;", - - "}", - - "void main() {", - - "gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );", - - //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );", - //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );", - //"gl_FragData[ 0 ] = pack_depth( z );", - //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", - - "}" - - ].join("\n") - - }, - - // Depth encoding into RGBA texture - // based on SpiderGL shadow map example - // http://spidergl.org/example.php?id=6 - // originally from - // http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD - // see also here: - // http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ - - 'linearDepthRGBA': { - - uniforms: { - "zNear": { type: "f", value: 0.5 }, - "zFar": { type: "f", value: 1000 } - }, - - vertexShader: [ - - THREE.ShaderChunk[ "common" ], - THREE.ShaderChunk[ "morphtarget_pars_vertex" ], - THREE.ShaderChunk[ "skinning_pars_vertex" ], - - "varying vec3 vViewPosition;", - - "void main() {", - - THREE.ShaderChunk[ "skinbase_vertex" ], - THREE.ShaderChunk[ "morphtarget_vertex" ], - THREE.ShaderChunk[ "skinning_vertex" ], - THREE.ShaderChunk[ "default_vertex" ], - - "vViewPosition = -mvPosition.xyz;", - - "}" - - ].join("\n"), - - fragmentShader: [ - - "uniform float zNear;", - "uniform float zFar;", - - "varying vec3 vViewPosition;", - - "vec4 pack_depth( const float depth ) {", - - " const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", - " const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", - " vec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );", // " vec4 res = fract( depth * bit_shift );", - " res -= res.xxyz * bit_mask;", - " return res;", - - "}", - - "void main() {", - - "gl_FragColor = pack_depth( clamp( ( vViewPosition.z - zNear ) / ( zFar - zNear ), 0.0, 1.0 ) );", - - //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );", - //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );", - //"gl_FragData[ 0 ] = pack_depth( z );", - //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", - - "}" - - ].join("\n") - - } - -}; - -/** - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author szimek / https://github.com/szimek/ - * @author bhouston / http://clara.io/ - */ - -THREE.WebGLRenderer = function ( parameters ) { - - console.log( 'THREE.WebGLRenderer', THREE.REVISION ); - - parameters = parameters || {}; - - var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), - _context = parameters.context !== undefined ? parameters.context : null, - - _precision = parameters.precision !== undefined ? parameters.precision : 'mediump', - - _buffers = {}, - - _alpha = parameters.alpha !== undefined ? parameters.alpha : false, - _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, - _antialias = parameters.antialias !== undefined ? parameters.antialias : false, - _stencil = parameters.stencil !== undefined ? parameters.stencil : true, - _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, - - _clearColor = new THREE.Color( 0x000000 ), - _clearAlpha = 0; - - // public properties - - this.domElement = _canvas; - this.context = null; - this.devicePixelRatio = parameters.devicePixelRatio !== undefined - ? parameters.devicePixelRatio - : self.devicePixelRatio !== undefined - ? self.devicePixelRatio - : 1; - - // clearing - - this.autoClear = true; - this.autoClearColor = true; - this.autoClearDepth = true; - this.autoClearStencil = true; - - // scene graph - - this.sortObjects = true; - this.autoUpdateObjects = true; - - // physically based shading - - this.gammaInput = true; - this.gammaOutput = true; - - // shadow map - - this.shadowMapEnabled = false; - this.shadowMapAutoUpdate = true; - this.shadowMapType = THREE.PCFShadowMap; - this.shadowMapCullFace = THREE.CullFaceFront; - this.shadowMapDebug = false; - this.shadowMapCascade = false; - - // morphs - - this.maxMorphTargets = 8; - this.maxMorphNormals = 4; - - // flags - - this.autoScaleCubemaps = true; - - // custom render plugins - - this.renderPluginsPre = []; - this.renderPluginsPost = []; - - // info - - this.info = { - - memory: { - - programs: 0, - geometries: 0, - textures: 0 - - }, - - render: { - - calls: 0, - vertices: 0, - faces: 0, - points: 0 - - } - - }; - - // internal properties - - var _this = this, - - _programs = [], - _programs_counter = 0, - - // internal state cache - - _currentProgram = null, - _currentFramebuffer = null, - _currentMaterialId = -1, - _currentGeometryGroupHash = null, - _currentCamera = null, - - _usedTextureUnits = 0, - - // GL state cache - - _oldDoubleSided = -1, - _oldFlipSided = -1, - - _oldBlending = -1, - - _oldBlendEquation = -1, - _oldBlendSrc = -1, - _oldBlendDst = -1, - - _oldDepthTest = -1, - _oldDepthWrite = -1, - - _oldPolygonOffset = null, - _oldPolygonOffsetFactor = null, - _oldPolygonOffsetUnits = null, - - _oldLineWidth = null, - - _viewportX = 0, - _viewportY = 0, - _viewportWidth = _canvas.width, - _viewportHeight = _canvas.height, - _currentWidth = 0, - _currentHeight = 0, - - _enabledAttributes = new Uint8Array( 16 ), - - // frustum - - _frustum = new THREE.Frustum(), - - // camera matrices cache - - _projScreenMatrix = new THREE.Matrix4(), - _projScreenMatrixPS = new THREE.Matrix4(), - - _vector3 = new THREE.Vector3(), - _width = new THREE.Vector3(), - _height = new THREE.Vector3(), - - // light arrays cache - - _direction = new THREE.Vector3(), - - _lightsNeedUpdate = true, - - _lights = { - - ambient: [ 0, 0, 0 ], - directional: { length: 0, colors: new Array(), positions: new Array() }, - point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), decayExponents: new Array() }, - spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), decayExponents: new Array(), directions: new Array(), anglesCos: new Array(), exponents: new Array() }, - hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() }, - area: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), decayExponents: new Array(), widths: new Array(), heights: new Array() } - - }; - - // initialize - - var _gl; - - var _glExtensionTextureFloat; - var _glExtensionTextureFloatLinear; - var _glExtensionStandardDerivatives; - var _glExtensionShaderTextureLOD; - var _glExtensionTextureFilterAnisotropic; - var _glExtensionCompressedTextureS3TC; - - initGL(); - - setDefaultGLState(); - - this.context = _gl; - - // GPU capabilities - - var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS ); - var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); - var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE ); - var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE ); - - var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0; - - var _supportsVertexTextures = ( _maxVertexTextures > 0 ); - var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat; - - var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : []; - - // - - var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT ); - var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT ); - var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT ); - - var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT ); - var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT ); - var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT ); - - var _vertexShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_INT ); - var _vertexShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_INT ); - var _vertexShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_INT ); - - var _fragmentShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_INT ); - var _fragmentShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_INT ); - var _fragmentShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_INT ); - - // clamp precision to maximum available - - var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0; - var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0; - - if ( _precision === "highp" && ! highpAvailable ) { - - if ( mediumpAvailable ) { - - _precision = "mediump"; - THREE.onwarning( "WebGLRenderer: highp not supported, using mediump" ); - - } else { - - _precision = "lowp"; - THREE.onwarning( "WebGLRenderer: highp and mediump not supported, using lowp" ); - - } - - } - - if ( _precision === "mediump" && ! mediumpAvailable ) { - - _precision = "lowp"; - THREE.onwarning( "WebGLRenderer: mediump not supported, using lowp" ); - - } - - // API - - this.getContext = function () { - - return _gl; - - }; - - this.supportsVertexTextures = function () { - - return _supportsVertexTextures; - - }; - - this.supportsFloatTextures = function () { - - return _glExtensionTextureFloat; - - }; - - this.supportsStandardDerivatives = function () { - - return _glExtensionStandardDerivatives; - - }; - - this.supportsCompressedTextureS3TC = function () { - - return _glExtensionCompressedTextureS3TC; - - }; - - this.getMaxAnisotropy = function () { - - return _maxAnisotropy; - - }; - - this.getPrecision = function () { - - return _precision; - - }; - - this.setSize = function ( width, height, updateStyle ) { - - _canvas.width = width * this.devicePixelRatio; - _canvas.height = height * this.devicePixelRatio; - - if ( this.devicePixelRatio !== 1 && updateStyle !== false ) { - - _canvas.style.width = width + 'px'; - _canvas.style.height = height + 'px'; - - } - - this.setViewport( 0, 0, width, height ); - - }; - - this.setViewport = function ( x, y, width, height ) { - - _viewportX = x * this.devicePixelRatio; - _viewportY = y * this.devicePixelRatio; - - _viewportWidth = width * this.devicePixelRatio; - _viewportHeight = height * this.devicePixelRatio; - - _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); - - }; - - this.setScissor = function ( x, y, width, height ) { - - _gl.scissor( - x * this.devicePixelRatio, - y * this.devicePixelRatio, - width * this.devicePixelRatio, - height * this.devicePixelRatio - ); - - }; - - this.enableScissorTest = function ( enable ) { - - enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST ); - - }; - - // Clearing - - this.setClearColor = function ( color, alpha ) { - - _clearColor.set( color ); - _clearAlpha = alpha !== undefined ? alpha : 1; - - _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); - - }; - - this.setClearColorHex = function ( hex, alpha ) { - - THREE.onwarning( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); - this.setClearColor( hex, alpha ); - - }; - - this.getClearColor = function () { - - return _clearColor; - - }; - - this.getClearAlpha = function () { - - return _clearAlpha; - - }; - - this.clear = function ( color, depth, stencil ) { - - var bits = 0; - - if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT; - if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT; - if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT; - - _gl.clear( bits ); - - }; - - this.clearColor = function () { - - _gl.clear( _gl.COLOR_BUFFER_BIT ); - - }; - - this.clearDepth = function () { - - _gl.clear( _gl.DEPTH_BUFFER_BIT ); - - }; - - this.clearStencil = function () { - - _gl.clear( _gl.STENCIL_BUFFER_BIT ); - - }; - - this.clearTarget = function ( renderTarget, color, depth, stencil ) { - - this.setRenderTarget( renderTarget ); - this.clear( color, depth, stencil ); - - }; - - // Plugins - - this.addPostPlugin = function ( plugin ) { - - plugin.init( this ); - this.renderPluginsPost.push( plugin ); - - }; - - this.addPrePlugin = function ( plugin ) { - - plugin.init( this ); - this.renderPluginsPre.push( plugin ); - - }; - - // Rendering - - this.updateShadowMap = function ( scene, camera ) { - - _currentProgram = null; - _oldBlending = -1; - _oldDepthTest = -1; - _oldDepthWrite = -1; - _currentGeometryGroupHash = -1; - _currentMaterialId = -1; - _lightsNeedUpdate = true; - _oldDoubleSided = -1; - _oldFlipSided = -1; - - this.shadowMapPlugin.update( scene, camera ); - - }; - - // Internal functions - - // Buffer allocation - - function createParticleBuffers ( geometry ) { - - geometry.__webglVertexBuffer = _gl.createBuffer(); - geometry.__webglColorBuffer = _gl.createBuffer(); - - _this.info.memory.geometries ++; - - }; - - function createLineBuffers ( geometry ) { - - geometry.__webglVertexBuffer = _gl.createBuffer(); - geometry.__webglColorBuffer = _gl.createBuffer(); - geometry.__webglLineDistanceBuffer = _gl.createBuffer(); - - _this.info.memory.geometries ++; - - }; - - function createMeshBuffers ( geometryGroup ) { - - geometryGroup.__webglVertexBuffer = _gl.createBuffer(); - geometryGroup.__webglNormalBuffer = _gl.createBuffer(); - geometryGroup.__webglTangentBuffer = _gl.createBuffer(); - geometryGroup.__webglColorBuffer = _gl.createBuffer(); - geometryGroup.__webglUVBuffer = _gl.createBuffer(); - geometryGroup.__webglUV2Buffer = _gl.createBuffer(); - - geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer(); - geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer(); - - geometryGroup.__webglFaceBuffer = _gl.createBuffer(); - geometryGroup.__webglLineBuffer = _gl.createBuffer(); - - var m, ml; - - if ( geometryGroup.numMorphTargets ) { - - geometryGroup.__webglMorphTargetsBuffers = []; - - for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { - - geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() ); - - } - - } - - if ( geometryGroup.numMorphNormals ) { - - geometryGroup.__webglMorphNormalsBuffers = []; - - for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { - - geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() ); - - } - - } - - _this.info.memory.geometries ++; - - }; - - // Events - - var onGeometryDispose = function ( event ) { - - var geometry = event.target; - - geometry.removeEventListener( 'dispose', onGeometryDispose ); - - deallocateGeometry( geometry ); - - }; - - var onTextureDispose = function ( event ) { - - var texture = event.target; - - texture.removeEventListener( 'dispose', onTextureDispose ); - - deallocateTexture( texture ); - - _this.info.memory.textures --; - - - }; - - var onRenderTargetDispose = function ( event ) { - - var renderTarget = event.target; - - renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); - - deallocateRenderTarget( renderTarget ); - - _this.info.memory.textures --; - - }; - - var onMaterialDispose = function ( event ) { - - var material = event.target; - - material.removeEventListener( 'dispose', onMaterialDispose ); - - deallocateMaterial( material ); - - }; - - // Buffer deallocation - - var deleteBuffers = function ( geometry ) { - - if ( geometry.__webglVertexBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglVertexBuffer ); - if ( geometry.__webglNormalBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglNormalBuffer ); - if ( geometry.__webglTangentBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglTangentBuffer ); - if ( geometry.__webglColorBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglColorBuffer ); - if ( geometry.__webglUVBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglUVBuffer ); - if ( geometry.__webglUV2Buffer !== undefined ) _gl.deleteBuffer( geometry.__webglUV2Buffer ); - - if ( geometry.__webglSkinIndicesBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinIndicesBuffer ); - if ( geometry.__webglSkinWeightsBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinWeightsBuffer ); - - if ( geometry.__webglFaceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglFaceBuffer ); - if ( geometry.__webglLineBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineBuffer ); - - if ( geometry.__webglLineDistanceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineDistanceBuffer ); - // custom attributes - - if ( geometry.__webglCustomAttributesList !== undefined ) { - - for ( var id in geometry.__webglCustomAttributesList ) { - - _gl.deleteBuffer( geometry.__webglCustomAttributesList[ id ].buffer ); - - } - - } - - _this.info.memory.geometries --; - - }; - - var deallocateGeometry = function ( geometry ) { - - geometry.__webglInit = undefined; - - if ( geometry instanceof THREE.BufferGeometry ) { - - var attributes = geometry.attributes; - - for ( var key in attributes ) { - - if ( attributes[ key ].buffer !== undefined ) { - - _gl.deleteBuffer( attributes[ key ].buffer ); - - } - - } - - _this.info.memory.geometries --; - - } else { - - if ( geometry.geometryGroups !== undefined ) { - - for ( var g in geometry.geometryGroups ) { - - var geometryGroup = geometry.geometryGroups[ g ]; - - if ( geometryGroup.numMorphTargets !== undefined ) { - - for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { - - _gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] ); - - } - - } - - if ( geometryGroup.numMorphNormals !== undefined ) { - - for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { - - _gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] ); - - } - - } - - deleteBuffers( geometryGroup ); - - } - - } else { - - deleteBuffers( geometry ); - - } - - } - - }; - - var deallocateTexture = function ( texture ) { - - if ( texture.image && texture.image.__webglTextureCube ) { - - // cube texture - - _gl.deleteTexture( texture.image.__webglTextureCube ); - - } else { - - // 2D texture - - if ( ! texture.__webglInit ) return; - - texture.__webglInit = false; - _gl.deleteTexture( texture.__webglTexture ); - - } - - }; - - var deallocateRenderTarget = function ( renderTarget ) { - - if ( !renderTarget || ! renderTarget.__webglTexture ) return; - - _gl.deleteTexture( renderTarget.__webglTexture ); - - if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { - - for ( var i = 0; i < 6; i ++ ) { - - _gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] ); - _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] ); - - } - - } else { - - _gl.deleteFramebuffer( renderTarget.__webglFramebuffer ); - _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer ); - - } - - }; - - var deallocateMaterial = function ( material, optionalDisconnectedProgram ) { - - var program = optionalDisconnectedProgram || material.program; - - if ( program === undefined ) return; - - if( ! optionalDisconnectedProgram ) { - material.program = undefined; - } - - // only deallocate GL program if this was the last use of shared program - // assumed there is only single copy of any program in the _programs list - // (that's how it's constructed) - - var i, il, programInfo; - var deleteProgram = false; - - for ( i = 0, il = _programs.length; i < il; i ++ ) { - - programInfo = _programs[ i ]; - - if ( programInfo.program === program ) { - - programInfo.usedTimes --; - - if ( programInfo.usedTimes === 0 ) { - - deleteProgram = true; - - } - - break; - - } - - } - - if ( deleteProgram === true ) { - - // avoid using array.splice, this is costlier than creating new array from scratch - - var newPrograms = []; - - for ( i = 0, il = _programs.length; i < il; i ++ ) { - - programInfo = _programs[ i ]; - - if ( programInfo.program !== program ) { - - newPrograms.push( programInfo ); - - } - - } - - _programs = newPrograms; - - _gl.deleteProgram( program ); - - _this.info.memory.programs --; - - } - - }; - - // Buffer initialization - - function initCustomAttributes ( geometry, object ) { - - var nvertices = geometry.vertices.length; - - var material = object.material; - - if ( material.attributes ) { - - if ( geometry.__webglCustomAttributesList === undefined ) { - - geometry.__webglCustomAttributesList = []; - - } - - for ( var a in material.attributes ) { - - var attribute = material.attributes[ a ]; - - if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { - - attribute.__webglInitialized = true; - - var size = 1; // "f" and "i" - - if ( attribute.type === "v2" ) size = 2; - else if ( attribute.type === "v3" ) size = 3; - else if ( attribute.type === "v4" ) size = 4; - else if ( attribute.type === "c" ) size = 3; - - attribute.size = size; - - attribute.array = new Float32Array( nvertices * size ); - - attribute.buffer = _gl.createBuffer(); - attribute.buffer.belongsToAttribute = a; - - attribute.needsUpdate = true; - - } - - geometry.__webglCustomAttributesList.push( attribute ); - - } - - } - - }; - - function initParticleBuffers ( geometry, object ) { - - var nvertices = geometry.vertices.length; - - geometry.__vertexArray = new Float32Array( nvertices * 3 ); - geometry.__colorArray = new Float32Array( nvertices * 3 ); - - geometry.__sortArray = []; - - geometry.__webglParticleCount = nvertices; - - initCustomAttributes ( geometry, object ); - - }; - - function initLineBuffers ( geometry, object ) { - - var nvertices = geometry.vertices.length; - - geometry.__vertexArray = new Float32Array( nvertices * 3 ); - geometry.__colorArray = new Float32Array( nvertices * 3 ); - geometry.__lineDistanceArray = new Float32Array( nvertices * 1 ); - - geometry.__webglLineCount = nvertices; - - initCustomAttributes ( geometry, object ); - - }; - - function initMeshBuffers ( geometryGroup, object ) { - - var geometry = object.geometry, - faces3 = geometryGroup.faces3, - - nvertices = faces3.length * 3, - ntris = faces3.length * 1, - nlines = faces3.length * 3, - - material = getBufferMaterial( object, geometryGroup ), - - uvType = bufferGuessUVType( material ), - normalType = bufferGuessNormalType( material ), - vertexColorType = bufferGuessVertexColorType( material ); - - geometryGroup.__vertexArray = new Float32Array( nvertices * 3 ); - - if ( normalType ) { - - geometryGroup.__normalArray = new Float32Array( nvertices * 3 ); - - } - - if ( geometry.hasTangents ) { - - geometryGroup.__tangentArray = new Float32Array( nvertices * 4 ); - - } - - if ( vertexColorType ) { - - geometryGroup.__colorArray = new Float32Array( nvertices * 3 ); - - } - - if ( uvType ) { - - if ( geometry.faceVertexUvs.length > 0 ) { - - geometryGroup.__uvArray = new Float32Array( nvertices * 2 ); - - } - - if ( geometry.faceVertexUvs.length > 1 ) { - - geometryGroup.__uv2Array = new Float32Array( nvertices * 2 ); - - } - - } - - if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) { - - geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 ); - geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 ); - - } - - geometryGroup.__faceArray = new Uint16Array( ntris * 3 ); - geometryGroup.__lineArray = new Uint16Array( nlines * 2 ); - - var m, ml; - - if ( geometryGroup.numMorphTargets ) { - - geometryGroup.__morphTargetsArrays = []; - - for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { - - geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) ); - - } - - } - - if ( geometryGroup.numMorphNormals ) { - - geometryGroup.__morphNormalsArrays = []; - - for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { - - geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) ); - - } - - } - - geometryGroup.__webglFaceCount = ntris * 3; - geometryGroup.__webglLineCount = nlines * 2; - - - // custom attributes - - if ( material.attributes ) { - - if ( geometryGroup.__webglCustomAttributesList === undefined ) { - - geometryGroup.__webglCustomAttributesList = []; - - } - - for ( var a in material.attributes ) { - - // Do a shallow copy of the attribute object so different geometryGroup chunks use different - // attribute buffers which are correctly indexed in the setMeshBuffers function - - var originalAttribute = material.attributes[ a ]; - - var attribute = {}; - - for ( var property in originalAttribute ) { - - attribute[ property ] = originalAttribute[ property ]; - - } - - if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { - - attribute.__webglInitialized = true; - - var size = 1; // "f" and "i" - - if( attribute.type === "v2" ) size = 2; - else if( attribute.type === "v3" ) size = 3; - else if( attribute.type === "v4" ) size = 4; - else if( attribute.type === "c" ) size = 3; - - attribute.size = size; - - attribute.array = new Float32Array( nvertices * size ); - - attribute.buffer = _gl.createBuffer(); - attribute.buffer.belongsToAttribute = a; - - originalAttribute.needsUpdate = true; - attribute.__original = originalAttribute; - - } - - geometryGroup.__webglCustomAttributesList.push( attribute ); - - } - - } - - geometryGroup.__inittedArrays = true; - - }; - - function getBufferMaterial( object, geometryGroup ) { - - return object.material instanceof THREE.MeshFaceMaterial - ? object.material.materials[ geometryGroup.materialIndex ] - : object.material; - - }; - - function materialNeedsSmoothNormals ( material ) { - - return material && material.shading !== undefined && material.shading === THREE.SmoothShading; - - }; - - function bufferGuessNormalType ( material ) { - - // only MeshBasicMaterial and MeshDepthMaterial don't need normals - - if ( ( material instanceof THREE.MeshBasicMaterial && !material.envMap ) || material instanceof THREE.MeshDepthMaterial ) { - - return false; - - } - - if ( materialNeedsSmoothNormals( material ) ) { - - return THREE.SmoothShading; - - } else { - - return THREE.FlatShading; - - } - - }; - - function bufferGuessVertexColorType( material ) { - - if ( material.vertexColors ) { - - return material.vertexColors; - - } - - return false; - - }; - - function bufferGuessUVType( material ) { - - // material must use some texture to require uvs - - if ( material.map || - material.opacityMap || - material.lightMap || - material.emissiveMap || - material.bumpMap || - material.normalMap || - material.specularMap || - material.reflectivityMap || - material.roughnessMap || - material.falloffMap || - material.anisotropyMap || - material.anisotropyRotationMap || - material.metallicMap || - material.translucencyMap || - ( material.anisotropy && material.anisotropy !== 0.0 ) || - material instanceof THREE.ShaderMaterial ) { - - return true; - - } - - return true; - - }; - - // - - function initDirectBuffers( geometry ) { - - var a, attribute, type; - - for ( a in geometry.attributes ) { - - if ( a === "index" ) { - - type = _gl.ELEMENT_ARRAY_BUFFER; - - } else { - - type = _gl.ARRAY_BUFFER; - - } - - attribute = geometry.attributes[ a ]; - - attribute.buffer = _gl.createBuffer(); - - _gl.bindBuffer( type, attribute.buffer ); - _gl.bufferData( type, attribute.array, _gl.STATIC_DRAW ); - - } - - }; - - // Buffer setting - - function setParticleBuffers ( geometry, hint, object ) { - - var v, c, vertex, offset, index, color, - - vertices = geometry.vertices, - vl = vertices.length, - - colors = geometry.colors, - cl = colors.length, - - vertexArray = geometry.__vertexArray, - colorArray = geometry.__colorArray, - - sortArray = geometry.__sortArray, - - dirtyVertices = geometry.verticesNeedUpdate, - dirtyElements = geometry.elementsNeedUpdate, - dirtyColors = geometry.colorsNeedUpdate, - - customAttributes = geometry.__webglCustomAttributesList, - i, il, - a, ca, cal, value, - customAttribute; - - if ( object.sortParticles ) { - - _projScreenMatrixPS.copy( _projScreenMatrix ); - _projScreenMatrixPS.multiply( object.matrixWorld ); - - for ( v = 0; v < vl; v ++ ) { - - vertex = vertices[ v ]; - - _vector3.copy( vertex ); - _vector3.applyProjection( _projScreenMatrixPS ); - - sortArray[ v ] = [ _vector3.z, v ]; - - } - - sortArray.sort( numericalSort ); - - for ( v = 0; v < vl; v ++ ) { - - vertex = vertices[ sortArray[v][1] ]; - - offset = v * 3; - - vertexArray[ offset ] = vertex.x; - vertexArray[ offset + 1 ] = vertex.y; - vertexArray[ offset + 2 ] = vertex.z; - - } - - for ( c = 0; c < cl; c ++ ) { - - offset = c * 3; - - color = colors[ sortArray[c][1] ]; - - colorArray[ offset ] = color.r; - colorArray[ offset + 1 ] = color.g; - colorArray[ offset + 2 ] = color.b; - - } - - if ( customAttributes ) { - - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - - customAttribute = customAttributes[ i ]; - - if ( ! ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) continue; - - offset = 0; - - cal = customAttribute.value.length; - - if ( customAttribute.size === 1 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - index = sortArray[ ca ][ 1 ]; - - customAttribute.array[ ca ] = customAttribute.value[ index ]; - - } - - } else if ( customAttribute.size === 2 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - index = sortArray[ ca ][ 1 ]; - - value = customAttribute.value[ index ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - - offset += 2; - - } - - } else if ( customAttribute.size === 3 ) { - - if ( customAttribute.type === "c" ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - index = sortArray[ ca ][ 1 ]; - - value = customAttribute.value[ index ]; - - customAttribute.array[ offset ] = value.r; - customAttribute.array[ offset + 1 ] = value.g; - customAttribute.array[ offset + 2 ] = value.b; - - offset += 3; - - } - - } else { - - for ( ca = 0; ca < cal; ca ++ ) { - - index = sortArray[ ca ][ 1 ]; - - value = customAttribute.value[ index ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - - offset += 3; - - } - - } - - } else if ( customAttribute.size === 4 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - index = sortArray[ ca ][ 1 ]; - - value = customAttribute.value[ index ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - customAttribute.array[ offset + 3 ] = value.w; - - offset += 4; - - } - - } - - } - - } - - } else { - - if ( dirtyVertices ) { - - for ( v = 0; v < vl; v ++ ) { - - vertex = vertices[ v ]; - - offset = v * 3; - - vertexArray[ offset ] = vertex.x; - vertexArray[ offset + 1 ] = vertex.y; - vertexArray[ offset + 2 ] = vertex.z; - - } - - } - - if ( dirtyColors ) { - - for ( c = 0; c < cl; c ++ ) { - - color = colors[ c ]; - - offset = c * 3; - - colorArray[ offset ] = color.r; - colorArray[ offset + 1 ] = color.g; - colorArray[ offset + 2 ] = color.b; - - } - - } - - if ( customAttributes ) { - - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - - customAttribute = customAttributes[ i ]; - - if ( customAttribute.needsUpdate && - ( customAttribute.boundTo === undefined || - customAttribute.boundTo === "vertices") ) { - - cal = customAttribute.value.length; - - offset = 0; - - if ( customAttribute.size === 1 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - customAttribute.array[ ca ] = customAttribute.value[ ca ]; - - } - - } else if ( customAttribute.size === 2 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - - offset += 2; - - } - - } else if ( customAttribute.size === 3 ) { - - if ( customAttribute.type === "c" ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.r; - customAttribute.array[ offset + 1 ] = value.g; - customAttribute.array[ offset + 2 ] = value.b; - - offset += 3; - - } - - } else { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - - offset += 3; - - } - - } - - } else if ( customAttribute.size === 4 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - customAttribute.array[ offset + 3 ] = value.w; - - offset += 4; - - } - - } - - } - - } - - } - - } - - if ( dirtyVertices || object.sortParticles ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); - - } - - if ( dirtyColors || object.sortParticles ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); - - } - - if ( customAttributes ) { - - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - - customAttribute = customAttributes[ i ]; - - if ( customAttribute.needsUpdate || object.sortParticles ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); - - } - - } - - } - - - }; - - function setLineBuffers ( geometry, hint ) { - - var v, c, d, vertex, offset, color, - - vertices = geometry.vertices, - colors = geometry.colors, - lineDistances = geometry.lineDistances, - - vl = vertices.length, - cl = colors.length, - dl = lineDistances.length, - - vertexArray = geometry.__vertexArray, - colorArray = geometry.__colorArray, - lineDistanceArray = geometry.__lineDistanceArray, - - dirtyVertices = geometry.verticesNeedUpdate, - dirtyColors = geometry.colorsNeedUpdate, - dirtyLineDistances = geometry.lineDistancesNeedUpdate, - - customAttributes = geometry.__webglCustomAttributesList, - - i, il, - a, ca, cal, value, - customAttribute; - - if ( dirtyVertices ) { - - for ( v = 0; v < vl; v ++ ) { - - vertex = vertices[ v ]; - - offset = v * 3; - - vertexArray[ offset ] = vertex.x; - vertexArray[ offset + 1 ] = vertex.y; - vertexArray[ offset + 2 ] = vertex.z; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); - - } - - if ( dirtyColors ) { - - for ( c = 0; c < cl; c ++ ) { - - color = colors[ c ]; - - offset = c * 3; - - colorArray[ offset ] = color.r; - colorArray[ offset + 1 ] = color.g; - colorArray[ offset + 2 ] = color.b; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); - - } - - if ( dirtyLineDistances ) { - - for ( d = 0; d < dl; d ++ ) { - - lineDistanceArray[ d ] = lineDistances[ d ]; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint ); - - } - - if ( customAttributes ) { - - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - - customAttribute = customAttributes[ i ]; - - if ( customAttribute.needsUpdate && - ( customAttribute.boundTo === undefined || - customAttribute.boundTo === "vertices" ) ) { - - offset = 0; - - cal = customAttribute.value.length; - - if ( customAttribute.size === 1 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - customAttribute.array[ ca ] = customAttribute.value[ ca ]; - - } - - } else if ( customAttribute.size === 2 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - - offset += 2; - - } - - } else if ( customAttribute.size === 3 ) { - - if ( customAttribute.type === "c" ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.r; - customAttribute.array[ offset + 1 ] = value.g; - customAttribute.array[ offset + 2 ] = value.b; - - offset += 3; - - } - - } else { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - - offset += 3; - - } - - } - - } else if ( customAttribute.size === 4 ) { - - for ( ca = 0; ca < cal; ca ++ ) { - - value = customAttribute.value[ ca ]; - - customAttribute.array[ offset ] = value.x; - customAttribute.array[ offset + 1 ] = value.y; - customAttribute.array[ offset + 2 ] = value.z; - customAttribute.array[ offset + 3 ] = value.w; - - offset += 4; - - } - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); - - } - - } - - } - - }; - - function setMeshBuffers( geometryGroup, object, hint, dispose, material ) { - - if ( ! geometryGroup.__inittedArrays ) { - - return; - - } - - var normalType = bufferGuessNormalType( material ), - vertexColorType = bufferGuessVertexColorType( material ), - uvType = bufferGuessUVType( material ), - - needsSmoothNormals = ( normalType === THREE.SmoothShading ); - - var f, fl, fi, face, - vertexNormals, faceNormal, normal, - vertexColors, faceColor, - vertexTangents, - uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4, - c1, c2, c3, c4, - sw1, sw2, sw3, sw4, - si1, si2, si3, si4, - sa1, sa2, sa3, sa4, - sb1, sb2, sb3, sb4, - m, ml, i, il, - vn, uvi, uv2i, - vk, vkl, vka, - nka, chf, faceVertexNormals, - a, - - vertexIndex = 0, - - offset = 0, - offset_uv = 0, - offset_uv2 = 0, - offset_face = 0, - offset_normal = 0, - offset_tangent = 0, - offset_line = 0, - offset_color = 0, - offset_skin = 0, - offset_morphTarget = 0, - offset_custom = 0, - offset_customSrc = 0, - - value, - - vertexArray = geometryGroup.__vertexArray, - uvArray = geometryGroup.__uvArray, - uv2Array = geometryGroup.__uv2Array, - normalArray = geometryGroup.__normalArray, - tangentArray = geometryGroup.__tangentArray, - colorArray = geometryGroup.__colorArray, - - skinIndexArray = geometryGroup.__skinIndexArray, - skinWeightArray = geometryGroup.__skinWeightArray, - - morphTargetsArrays = geometryGroup.__morphTargetsArrays, - morphNormalsArrays = geometryGroup.__morphNormalsArrays, - - customAttributes = geometryGroup.__webglCustomAttributesList, - customAttribute, - - faceArray = geometryGroup.__faceArray, - lineArray = geometryGroup.__lineArray, - - geometry = object.geometry, // this is shared for all chunks - - dirtyVertices = geometry.verticesNeedUpdate, - dirtyElements = geometry.elementsNeedUpdate, - dirtyUvs = geometry.uvsNeedUpdate, - dirtyNormals = geometry.normalsNeedUpdate, - dirtyTangents = geometry.tangentsNeedUpdate, - dirtyColors = geometry.colorsNeedUpdate, - dirtyMorphTargets = geometry.morphTargetsNeedUpdate, - - vertices = geometry.vertices, - chunk_faces3 = geometryGroup.faces3, - obj_faces = geometry.faces, - - obj_uvs = geometry.faceVertexUvs[ 0 ], - obj_uvs2 = geometry.faceVertexUvs[ 1 ], - - obj_colors = geometry.colors, - - obj_skinIndices = geometry.skinIndices, - obj_skinWeights = geometry.skinWeights, - - morphTargets = geometry.morphTargets, - morphNormals = geometry.morphNormals; - - if ( dirtyVertices ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - v1 = vertices[ face.a ]; - v2 = vertices[ face.b ]; - v3 = vertices[ face.c ]; - - vertexArray[ offset ] = v1.x; - vertexArray[ offset + 1 ] = v1.y; - vertexArray[ offset + 2 ] = v1.z; - - vertexArray[ offset + 3 ] = v2.x; - vertexArray[ offset + 4 ] = v2.y; - vertexArray[ offset + 5 ] = v2.z; - - vertexArray[ offset + 6 ] = v3.x; - vertexArray[ offset + 7 ] = v3.y; - vertexArray[ offset + 8 ] = v3.z; - - offset += 9; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); - - } - - if ( dirtyMorphTargets ) { - - for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) { - - offset_morphTarget = 0; - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - chf = chunk_faces3[ f ]; - face = obj_faces[ chf ]; - - // morph positions - - v1 = morphTargets[ vk ].vertices[ face.a ]; - v2 = morphTargets[ vk ].vertices[ face.b ]; - v3 = morphTargets[ vk ].vertices[ face.c ]; - - vka = morphTargetsArrays[ vk ]; - - vka[ offset_morphTarget ] = v1.x; - vka[ offset_morphTarget + 1 ] = v1.y; - vka[ offset_morphTarget + 2 ] = v1.z; - - vka[ offset_morphTarget + 3 ] = v2.x; - vka[ offset_morphTarget + 4 ] = v2.y; - vka[ offset_morphTarget + 5 ] = v2.z; - - vka[ offset_morphTarget + 6 ] = v3.x; - vka[ offset_morphTarget + 7 ] = v3.y; - vka[ offset_morphTarget + 8 ] = v3.z; - - // morph normals - - if ( material.morphNormals ) { - - if ( needsSmoothNormals ) { - - faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ]; - - n1 = faceVertexNormals.a; - n2 = faceVertexNormals.b; - n3 = faceVertexNormals.c; - - } else { - - n1 = morphNormals[ vk ].faceNormals[ chf ]; - n2 = n1; - n3 = n1; - - } - - nka = morphNormalsArrays[ vk ]; - - nka[ offset_morphTarget ] = n1.x; - nka[ offset_morphTarget + 1 ] = n1.y; - nka[ offset_morphTarget + 2 ] = n1.z; - - nka[ offset_morphTarget + 3 ] = n2.x; - nka[ offset_morphTarget + 4 ] = n2.y; - nka[ offset_morphTarget + 5 ] = n2.z; - - nka[ offset_morphTarget + 6 ] = n3.x; - nka[ offset_morphTarget + 7 ] = n3.y; - nka[ offset_morphTarget + 8 ] = n3.z; - - } - - // - - offset_morphTarget += 9; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] ); - _gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint ); - - if ( material.morphNormals ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] ); - _gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint ); - - } - - } - - } - - if ( obj_skinWeights.length ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - // weights - - sw1 = obj_skinWeights[ face.a ]; - sw2 = obj_skinWeights[ face.b ]; - sw3 = obj_skinWeights[ face.c ]; - - skinWeightArray[ offset_skin ] = sw1.x; - skinWeightArray[ offset_skin + 1 ] = sw1.y; - skinWeightArray[ offset_skin + 2 ] = sw1.z; - skinWeightArray[ offset_skin + 3 ] = sw1.w; - - skinWeightArray[ offset_skin + 4 ] = sw2.x; - skinWeightArray[ offset_skin + 5 ] = sw2.y; - skinWeightArray[ offset_skin + 6 ] = sw2.z; - skinWeightArray[ offset_skin + 7 ] = sw2.w; - - skinWeightArray[ offset_skin + 8 ] = sw3.x; - skinWeightArray[ offset_skin + 9 ] = sw3.y; - skinWeightArray[ offset_skin + 10 ] = sw3.z; - skinWeightArray[ offset_skin + 11 ] = sw3.w; - - // indices - - si1 = obj_skinIndices[ face.a ]; - si2 = obj_skinIndices[ face.b ]; - si3 = obj_skinIndices[ face.c ]; - - skinIndexArray[ offset_skin ] = si1.x; - skinIndexArray[ offset_skin + 1 ] = si1.y; - skinIndexArray[ offset_skin + 2 ] = si1.z; - skinIndexArray[ offset_skin + 3 ] = si1.w; - - skinIndexArray[ offset_skin + 4 ] = si2.x; - skinIndexArray[ offset_skin + 5 ] = si2.y; - skinIndexArray[ offset_skin + 6 ] = si2.z; - skinIndexArray[ offset_skin + 7 ] = si2.w; - - skinIndexArray[ offset_skin + 8 ] = si3.x; - skinIndexArray[ offset_skin + 9 ] = si3.y; - skinIndexArray[ offset_skin + 10 ] = si3.z; - skinIndexArray[ offset_skin + 11 ] = si3.w; - - offset_skin += 12; - - } - - if ( offset_skin > 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint ); - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint ); - - } - - } - - if ( dirtyColors && vertexColorType ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - vertexColors = face.vertexColors; - faceColor = face.color; - - if ( vertexColors.length === 3 && vertexColorType === THREE.VertexColors ) { - - c1 = vertexColors[ 0 ]; - c2 = vertexColors[ 1 ]; - c3 = vertexColors[ 2 ]; - - } else { - - c1 = faceColor; - c2 = faceColor; - c3 = faceColor; - - } - - colorArray[ offset_color ] = c1.r; - colorArray[ offset_color + 1 ] = c1.g; - colorArray[ offset_color + 2 ] = c1.b; - - colorArray[ offset_color + 3 ] = c2.r; - colorArray[ offset_color + 4 ] = c2.g; - colorArray[ offset_color + 5 ] = c2.b; - - colorArray[ offset_color + 6 ] = c3.r; - colorArray[ offset_color + 7 ] = c3.g; - colorArray[ offset_color + 8 ] = c3.b; - - offset_color += 9; - - } - - if ( offset_color > 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); - - } - - } - - if ( dirtyTangents && geometry.hasTangents ) { - - var tmp = new THREE.Vector3( 0, 0, 0 ); - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - vertexTangents = face.vertexTangents; - - t1 = vertexTangents[ 0 ] || tmp; - t2 = vertexTangents[ 1 ] || tmp; - t3 = vertexTangents[ 2 ] || tmp; - - tangentArray[ offset_tangent ] = t1.x; - tangentArray[ offset_tangent + 1 ] = t1.y; - tangentArray[ offset_tangent + 2 ] = t1.z; - tangentArray[ offset_tangent + 3 ] = t1.w; - - tangentArray[ offset_tangent + 4 ] = t2.x; - tangentArray[ offset_tangent + 5 ] = t2.y; - tangentArray[ offset_tangent + 6 ] = t2.z; - tangentArray[ offset_tangent + 7 ] = t2.w; - - tangentArray[ offset_tangent + 8 ] = t3.x; - tangentArray[ offset_tangent + 9 ] = t3.y; - tangentArray[ offset_tangent + 10 ] = t3.z; - tangentArray[ offset_tangent + 11 ] = t3.w; - - offset_tangent += 12; - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint ); - - } - - if ( dirtyNormals && normalType ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - vertexNormals = face.vertexNormals; - faceNormal = face.normal; - - if ( vertexNormals.length === 3 && needsSmoothNormals ) { - - for ( i = 0; i < 3; i ++ ) { - - vn = vertexNormals[ i ]; - - normalArray[ offset_normal ] = vn.x; - normalArray[ offset_normal + 1 ] = vn.y; - normalArray[ offset_normal + 2 ] = vn.z; - - offset_normal += 3; - - } - - } else { - - for ( i = 0; i < 3; i ++ ) { - - normalArray[ offset_normal ] = faceNormal.x; - normalArray[ offset_normal + 1 ] = faceNormal.y; - normalArray[ offset_normal + 2 ] = faceNormal.z; - - offset_normal += 3; - - } - - } - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint ); - - } - - if ( dirtyUvs && obj_uvs && uvType ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - fi = chunk_faces3[ f ]; - - uv = obj_uvs[ fi ]; - - if ( uv === undefined ) continue; - - for ( i = 0; i < 3; i ++ ) { - - uvi = uv[ i ]; - - uvArray[ offset_uv ] = uvi.x; - uvArray[ offset_uv + 1 ] = uvi.y; - - offset_uv += 2; - - } - - } - - if ( offset_uv > 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint ); - - } - - } - - if ( dirtyUvs && obj_uvs2 && uvType ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - fi = chunk_faces3[ f ]; - - uv2 = obj_uvs2[ fi ]; - - if ( uv2 === undefined ) continue; - - for ( i = 0; i < 3; i ++ ) { - - uv2i = uv2[ i ]; - - uv2Array[ offset_uv2 ] = uv2i.x; - uv2Array[ offset_uv2 + 1 ] = uv2i.y; - - offset_uv2 += 2; - - } - - } - - if ( offset_uv2 > 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint ); - - } - - } - - if ( dirtyElements ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - faceArray[ offset_face ] = vertexIndex; - faceArray[ offset_face + 1 ] = vertexIndex + 1; - faceArray[ offset_face + 2 ] = vertexIndex + 2; - - offset_face += 3; - - lineArray[ offset_line ] = vertexIndex; - lineArray[ offset_line + 1 ] = vertexIndex + 1; - - lineArray[ offset_line + 2 ] = vertexIndex; - lineArray[ offset_line + 3 ] = vertexIndex + 2; - - lineArray[ offset_line + 4 ] = vertexIndex + 1; - lineArray[ offset_line + 5 ] = vertexIndex + 2; - - offset_line += 6; - - vertexIndex += 3; - - } - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint ); - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint ); - - } - - if ( customAttributes ) { - - for ( i = 0, il = customAttributes.length; i < il; i ++ ) { - - customAttribute = customAttributes[ i ]; - - if ( ! customAttribute.__original.needsUpdate ) continue; - - offset_custom = 0; - offset_customSrc = 0; - - if ( customAttribute.size === 1 ) { - - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ]; - customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ]; - customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ]; - - offset_custom += 3; - - } - - } else if ( customAttribute.boundTo === "faces" ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - value = customAttribute.value[ chunk_faces3[ f ] ]; - - customAttribute.array[ offset_custom ] = value; - customAttribute.array[ offset_custom + 1 ] = value; - customAttribute.array[ offset_custom + 2 ] = value; - - offset_custom += 3; - - } - - } - - } else if ( customAttribute.size === 2 ) { - - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - v1 = customAttribute.value[ face.a ]; - v2 = customAttribute.value[ face.b ]; - v3 = customAttribute.value[ face.c ]; - - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; - - customAttribute.array[ offset_custom + 2 ] = v2.x; - customAttribute.array[ offset_custom + 3 ] = v2.y; - - customAttribute.array[ offset_custom + 4 ] = v3.x; - customAttribute.array[ offset_custom + 5 ] = v3.y; - - offset_custom += 6; - - } - - } else if ( customAttribute.boundTo === "faces" ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - value = customAttribute.value[ chunk_faces3[ f ] ]; - - v1 = value; - v2 = value; - v3 = value; - - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; - - customAttribute.array[ offset_custom + 2 ] = v2.x; - customAttribute.array[ offset_custom + 3 ] = v2.y; - - customAttribute.array[ offset_custom + 4 ] = v3.x; - customAttribute.array[ offset_custom + 5 ] = v3.y; - - offset_custom += 6; - - } - - } - - } else if ( customAttribute.size === 3 ) { - - var pp; - - if ( customAttribute.type === "c" ) { - - pp = [ "r", "g", "b" ]; - - } else { - - pp = [ "x", "y", "z" ]; - - } - - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - v1 = customAttribute.value[ face.a ]; - v2 = customAttribute.value[ face.b ]; - v3 = customAttribute.value[ face.c ]; - - customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; - - customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; - - customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; - - offset_custom += 9; - - } - - } else if ( customAttribute.boundTo === "faces" ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - value = customAttribute.value[ chunk_faces3[ f ] ]; - - v1 = value; - v2 = value; - v3 = value; - - customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; - - customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; - - customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; - - offset_custom += 9; - - } - - } else if ( customAttribute.boundTo === "faceVertices" ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - value = customAttribute.value[ chunk_faces3[ f ] ]; - - v1 = value[ 0 ]; - v2 = value[ 1 ]; - v3 = value[ 2 ]; - - customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; - - customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; - - customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; - customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; - customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; - - offset_custom += 9; - - } - - } - - } else if ( customAttribute.size === 4 ) { - - if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - face = obj_faces[ chunk_faces3[ f ] ]; - - v1 = customAttribute.value[ face.a ]; - v2 = customAttribute.value[ face.b ]; - v3 = customAttribute.value[ face.c ]; - - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; - customAttribute.array[ offset_custom + 2 ] = v1.z; - customAttribute.array[ offset_custom + 3 ] = v1.w; - - customAttribute.array[ offset_custom + 4 ] = v2.x; - customAttribute.array[ offset_custom + 5 ] = v2.y; - customAttribute.array[ offset_custom + 6 ] = v2.z; - customAttribute.array[ offset_custom + 7 ] = v2.w; - - customAttribute.array[ offset_custom + 8 ] = v3.x; - customAttribute.array[ offset_custom + 9 ] = v3.y; - customAttribute.array[ offset_custom + 10 ] = v3.z; - customAttribute.array[ offset_custom + 11 ] = v3.w; - - offset_custom += 12; - - } - - } else if ( customAttribute.boundTo === "faces" ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - value = customAttribute.value[ chunk_faces3[ f ] ]; - - v1 = value; - v2 = value; - v3 = value; - - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; - customAttribute.array[ offset_custom + 2 ] = v1.z; - customAttribute.array[ offset_custom + 3 ] = v1.w; - - customAttribute.array[ offset_custom + 4 ] = v2.x; - customAttribute.array[ offset_custom + 5 ] = v2.y; - customAttribute.array[ offset_custom + 6 ] = v2.z; - customAttribute.array[ offset_custom + 7 ] = v2.w; - - customAttribute.array[ offset_custom + 8 ] = v3.x; - customAttribute.array[ offset_custom + 9 ] = v3.y; - customAttribute.array[ offset_custom + 10 ] = v3.z; - customAttribute.array[ offset_custom + 11 ] = v3.w; - - offset_custom += 12; - - } - - } else if ( customAttribute.boundTo === "faceVertices" ) { - - for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { - - value = customAttribute.value[ chunk_faces3[ f ] ]; - - v1 = value[ 0 ]; - v2 = value[ 1 ]; - v3 = value[ 2 ]; - - customAttribute.array[ offset_custom ] = v1.x; - customAttribute.array[ offset_custom + 1 ] = v1.y; - customAttribute.array[ offset_custom + 2 ] = v1.z; - customAttribute.array[ offset_custom + 3 ] = v1.w; - - customAttribute.array[ offset_custom + 4 ] = v2.x; - customAttribute.array[ offset_custom + 5 ] = v2.y; - customAttribute.array[ offset_custom + 6 ] = v2.z; - customAttribute.array[ offset_custom + 7 ] = v2.w; - - customAttribute.array[ offset_custom + 8 ] = v3.x; - customAttribute.array[ offset_custom + 9 ] = v3.y; - customAttribute.array[ offset_custom + 10 ] = v3.z; - customAttribute.array[ offset_custom + 11 ] = v3.w; - - offset_custom += 12; - - } - - } - - } - - _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); - - } - - } - - if ( dispose ) { - - delete geometryGroup.__inittedArrays; - delete geometryGroup.__colorArray; - delete geometryGroup.__normalArray; - delete geometryGroup.__tangentArray; - delete geometryGroup.__uvArray; - delete geometryGroup.__uv2Array; - delete geometryGroup.__faceArray; - delete geometryGroup.__vertexArray; - delete geometryGroup.__lineArray; - delete geometryGroup.__skinIndexArray; - delete geometryGroup.__skinWeightArray; - - } - - }; - - // used by renderBufferDirect for THREE.Line - function setupLinesVertexAttributes( material, programAttributes, geometryAttributes, startIndex ) { - - var attributeItem, attributeName, attributePointer, attributeSize; - - for ( attributeName in programAttributes ) { - - attributePointer = programAttributes[ attributeName ]; - attributeItem = geometryAttributes[ attributeName ]; - - if ( attributePointer >= 0 ) { - - if ( attributeItem ) { - - attributeSize = attributeItem.itemSize; - _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); - enableAttribute( attributePointer ); - _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, startIndex * attributeSize * 4 ); // 4 bytes per Float32 - - } else if ( material.defaultAttributeValues ) { - - if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { - - _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { - - _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } - - } - - } - - } - - } - - function setDirectBuffers( geometry, hint ) { - - var attributes = geometry.attributes; - - var attributeName, attributeItem; - - for ( attributeName in attributes ) { - - attributeItem = attributes[ attributeName ]; - - if ( attributeItem.needsUpdate ) { - - if ( attributeName === 'index' ) { - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.buffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.array, hint ); - - } else { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, attributeItem.array, hint ); - - } - - attributeItem.needsUpdate = false; - - } - - } - - } - - // Buffer rendering - - this.renderBufferImmediate = function ( object, program, material ) { - - if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer(); - if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer(); - if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer(); - if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer(); - - if ( object.hasPositions ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); - _gl.enableVertexAttribArray( program.attributes.position ); - _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - - } - - if ( object.hasNormals ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer ); - - if ( material.shading === THREE.FlatShading ) { - - var nx, ny, nz, - nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz, - normalArray, - i, il = object.count * 3; - - for( i = 0; i < il; i += 9 ) { - - normalArray = object.normalArray; - - nax = normalArray[ i ]; - nay = normalArray[ i + 1 ]; - naz = normalArray[ i + 2 ]; - - nbx = normalArray[ i + 3 ]; - nby = normalArray[ i + 4 ]; - nbz = normalArray[ i + 5 ]; - - ncx = normalArray[ i + 6 ]; - ncy = normalArray[ i + 7 ]; - ncz = normalArray[ i + 8 ]; - - nx = ( nax + nbx + ncx ) / 3; - ny = ( nay + nby + ncy ) / 3; - nz = ( naz + nbz + ncz ) / 3; - - normalArray[ i ] = nx; - normalArray[ i + 1 ] = ny; - normalArray[ i + 2 ] = nz; - - normalArray[ i + 3 ] = nx; - normalArray[ i + 4 ] = ny; - normalArray[ i + 5 ] = nz; - - normalArray[ i + 6 ] = nx; - normalArray[ i + 7 ] = ny; - normalArray[ i + 8 ] = nz; - - } - - } - - _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); - _gl.enableVertexAttribArray( program.attributes.normal ); - _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); - - } - - if ( object.hasUvs && material.map ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); - _gl.enableVertexAttribArray( program.attributes.uv ); - _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); - - } - - if ( object.hasColors && material.vertexColors !== THREE.NoColors ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); - _gl.enableVertexAttribArray( program.attributes.color ); - _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 ); - - } - - _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); - - object.count = 0; - - }; - - this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) { - - if ( material.visible === false ) return; - - var linewidth, a, attribute; - var attributeItem, attributeName, attributePointer, attributeSize; - - var program = setProgram( camera, lights, fog, material, object ); - - var programAttributes = program.attributes; - var geometryAttributes = geometry.attributes; - - var updateBuffers = false, - wireframeBit = material.wireframe ? 1 : 0, - geometryHash = ( geometry.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; - - if ( geometryHash !== _currentGeometryGroupHash ) { - - _currentGeometryGroupHash = geometryHash; - updateBuffers = true; - - } - - if ( updateBuffers ) { - - disableAttributes(); - - } - - // render mesh - - if ( object instanceof THREE.Mesh ) { - - var index = geometryAttributes[ "index" ]; - - // indexed triangles - - if ( index ) { - - var offsets = geometry.offsets; - - // if there is more than 1 chunk - // must set attribute pointers to use new offsets for each chunk - // even if geometry and materials didn't change - - if ( offsets.length > 1 ) updateBuffers = true; - - for ( var i = 0, il = offsets.length; i < il; i ++ ) { - - var startIndex = offsets[ i ].index; - - if ( updateBuffers ) { - - for ( attributeName in programAttributes ) { - - attributePointer = programAttributes[ attributeName ]; - attributeItem = geometryAttributes[ attributeName ]; - - if ( attributePointer >= 0 ) { - - if ( attributeItem ) { - - attributeSize = attributeItem.itemSize; - _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); - enableAttribute( attributePointer ); - _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, startIndex * attributeSize * 4 ); // 4 bytes per Float32 - - } else if ( material.defaultAttributeValues ) { - - if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { - - _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { - - _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } - - } - - } - - } - - // indices - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - - } - - // render indexed triangles - - _gl.drawElements( _gl.TRIANGLES, offsets[ i ].count, _gl.UNSIGNED_SHORT, offsets[ i ].start * 2 ); // 2 bytes per Uint16 - - _this.info.render.calls ++; - _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared - _this.info.render.faces += offsets[ i ].count / 3; - - } - - // non-indexed triangles - - } else { - - if ( updateBuffers ) { - - for ( attributeName in programAttributes ) { - - if ( attributeName === 'index') continue; - - attributePointer = programAttributes[ attributeName ]; - attributeItem = geometryAttributes[ attributeName ]; - - if ( attributePointer >= 0 ) { - - if ( attributeItem ) { - - attributeSize = attributeItem.itemSize; - _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); - enableAttribute( attributePointer ); - _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 ); - - } else if ( material.defaultAttributeValues && material.defaultAttributeValues[ attributeName ] ) { - - if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { - - _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { - - _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } - - } - - } - - } - - } - - var position = geometry.attributes[ "position" ]; - - // render non-indexed triangles - - _gl.drawArrays( _gl.TRIANGLES, 0, position.array.length / 3 ); - - _this.info.render.calls ++; - _this.info.render.vertices += position.array.length / 3; - _this.info.render.faces += position.array.length / 3 / 3; - - } - - // render particles - - } else if ( object instanceof THREE.ParticleSystem ) { - - if ( updateBuffers ) { - - for ( attributeName in programAttributes ) { - - attributePointer = programAttributes[ attributeName ]; - attributeItem = geometryAttributes[ attributeName ]; - - if ( attributePointer >= 0 ) { - - if ( attributeItem ) { - - attributeSize = attributeItem.itemSize; - _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); - enableAttribute( attributePointer ); - _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 ); - - } else if ( material.defaultAttributeValues && material.defaultAttributeValues[ attributeName ] ) { - - if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { - - _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { - - _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); - - } - - } - - } - - } - - } - - var position = geometryAttributes[ "position" ]; - - // render particles - - _gl.drawArrays( _gl.POINTS, 0, position.array.length / 3 ); - - _this.info.render.calls ++; - _this.info.render.points += position.array.length / 3; - - } else if ( object instanceof THREE.Line ) { - - var primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; - - setLineWidth( material.linewidth ); - - var index = geometryAttributes[ "index" ]; - - // indexed lines - - if ( index ) { - - var offsets = geometry.offsets; - - // if there is more than 1 chunk - // must set attribute pointers to use new offsets for each chunk - // even if geometry and materials didn't change - - if ( offsets.length > 1 ) updateBuffers = true; - - for ( var i = 0, il = offsets.length; i < il; i ++ ) { - - var startIndex = offsets[ i ].index; - - if ( updateBuffers ) { - - setupLinesVertexAttributes(material, programAttributes, geometryAttributes, startIndex); - - // indices - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); - - } - - // render indexed lines - - _gl.drawElements( _gl.LINES, offsets[ i ].count, _gl.UNSIGNED_SHORT, offsets[ i ].start * 2 ); // 2 bytes per Uint16Array - - _this.info.render.calls ++; - _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared - - } - - } - - // non-indexed lines - - else { - - if ( updateBuffers ) { - - setupLinesVertexAttributes(material, programAttributes, geometryAttributes, 0); - } - - var position = geometryAttributes[ "position" ]; - - _gl.drawArrays( primitives, 0, position.array.length / 3 ); - _this.info.render.calls ++; - _this.info.render.points += position.array.length; - } - - - - } - - }; - - this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) { - - if ( material.visible === false ) return; - - var linewidth, a, attribute, i, il; - - var program = setProgram( camera, lights, fog, material, object ); - - var attributes = program.attributes; - - var updateBuffers = false, - wireframeBit = material.wireframe ? 1 : 0, - geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; - - if ( geometryGroupHash !== _currentGeometryGroupHash ) { - - _currentGeometryGroupHash = geometryGroupHash; - updateBuffers = true; - - } - - if ( updateBuffers ) { - - disableAttributes(); - - } - - // vertices - - if ( !material.morphTargets && attributes.position >= 0 ) { - - if ( updateBuffers ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - enableAttribute( attributes.position ); - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - - } - - } else { - - if ( object.morphTargetBase ) { - - setupMorphTargets( material, geometryGroup, object ); - - } - - } - - - if ( updateBuffers ) { - - // custom attributes - - // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers - - if ( geometryGroup.__webglCustomAttributesList ) { - - for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) { - - attribute = geometryGroup.__webglCustomAttributesList[ i ]; - - if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer ); - enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); - _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 ); - - } - - } - - } - - - // colors - - if ( attributes.color >= 0 ) { - - if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); - enableAttribute( attributes.color ); - _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); - - } else if ( material.defaultAttributeValues ) { - - - _gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color ); - - } - - } - - // normals - - if ( attributes.normal >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); - enableAttribute( attributes.normal ); - _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); - - } - - // tangents - - if ( attributes.tangent >= 0 ) { - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); - enableAttribute( attributes.tangent ); - _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); - - } - - // uvs - - if ( attributes.uv >= 0 ) { - - if ( object.geometry.faceVertexUvs[0] ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); - enableAttribute( attributes.uv ); - _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); - - } else if ( material.defaultAttributeValues ) { - - - _gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv ); - - } - - } - - if ( attributes.uv2 >= 0 ) { - - if ( object.geometry.faceVertexUvs[1] ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); - enableAttribute( attributes.uv2 ); - _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 ); - - } else if ( material.defaultAttributeValues ) { - - - _gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 ); - - } - - } - - if ( material.skinning && - attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); - enableAttribute( attributes.skinIndex ); - _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 ); - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); - enableAttribute( attributes.skinWeight ); - _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 ); - - } - - // line distances - - if ( attributes.lineDistance >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer ); - enableAttribute( attributes.lineDistance ); - _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 ); - - } - - } - - // render mesh - - if ( object instanceof THREE.Mesh ) { - - // wireframe - - if ( material.wireframe ) { - - setLineWidth( material.wireframeLinewidth ); - - if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); - _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, _gl.UNSIGNED_SHORT, 0 ); - - // triangles - - } else { - - if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); - _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, _gl.UNSIGNED_SHORT, 0 ); - - } - - _this.info.render.calls ++; - _this.info.render.vertices += geometryGroup.__webglFaceCount; - _this.info.render.faces += geometryGroup.__webglFaceCount / 3; - - // render lines - - } else if ( object instanceof THREE.Line ) { - - var primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; - - setLineWidth( material.linewidth ); - - _gl.drawArrays( primitives, 0, geometryGroup.__webglLineCount ); - - _this.info.render.calls ++; - - // render particles - - } else if ( object instanceof THREE.ParticleSystem ) { - - _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount ); - - _this.info.render.calls ++; - _this.info.render.points += geometryGroup.__webglParticleCount; - - } - - }; - - function enableAttribute( attribute ) { - - if ( _enabledAttributes[ attribute ] === 0 ) { - - _gl.enableVertexAttribArray( attribute ); - _enabledAttributes[ attribute ] = 1; - - } - - }; - - function disableAttributes() { - - for ( var attribute in _enabledAttributes ) { - - if ( _enabledAttributes[ attribute ] === 1 ) { - - _gl.disableVertexAttribArray( attribute ); - _enabledAttributes[ attribute ] = 0; - - } - - } - - }; - - function setupMorphTargets ( material, geometryGroup, object ) { - - // set base - - var attributes = material.program.attributes; - - if ( object.morphTargetBase !== -1 && attributes.position >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] ); - enableAttribute( attributes.position ); - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - - } else if ( attributes.position >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - enableAttribute( attributes.position ); - _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); - - } - - if ( object.morphTargetForcedOrder.length ) { - - // set forced order - - var m = 0; - var order = object.morphTargetForcedOrder; - var influences = object.morphTargetInfluences; - - while ( m < material.numSupportedMorphTargets && m < order.length ) { - - if ( attributes[ "morphTarget" + m ] >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] ); - enableAttribute( attributes[ "morphTarget" + m ] ); - _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); - - } - - if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] ); - enableAttribute( attributes[ "morphNormal" + m ] ); - _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); - - } - - object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ]; - - m ++; - } - - } else { - - // find the most influencing - - var influence, activeInfluenceIndices = []; - var influences = object.morphTargetInfluences; - var i, il = influences.length; - - for ( i = 0; i < il; i ++ ) { - - influence = influences[ i ]; - - if ( influence > 0 ) { - - activeInfluenceIndices.push( [ influence, i ] ); - - } - - } - - if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) { - - activeInfluenceIndices.sort( numericalSort ); - activeInfluenceIndices.length = material.numSupportedMorphTargets; - - } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) { - - activeInfluenceIndices.sort( numericalSort ); - - } else if ( activeInfluenceIndices.length === 0 ) { - - activeInfluenceIndices.push( [ 0, 0 ] ); - - }; - - var influenceIndex, m = 0; - - while ( m < material.numSupportedMorphTargets ) { - - if ( activeInfluenceIndices[ m ] ) { - - influenceIndex = activeInfluenceIndices[ m ][ 1 ]; - - if ( attributes[ "morphTarget" + m ] >= 0 ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] ); - enableAttribute( attributes[ "morphTarget" + m ] ); - _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); - - } - - if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { - - _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] ); - enableAttribute( attributes[ "morphNormal" + m ] ); - _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); - - - } - - object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ]; - - } else { - - /* - _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); - - if ( material.morphNormals ) { - - _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); - - } - */ - - object.__webglMorphTargetInfluences[ m ] = 0; - - } - - m ++; - - } - - } - - // load updated influences uniform - - if ( material.program.uniforms.morphTargetInfluences !== null ) { - - _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences ); - - } - - }; - - // Sorting - - function painterSortStable ( a, b ) { - - if ( a.z !== b.z ) { - - return b.z - a.z; - - } else { - - return a.id - b.id; - - } - - }; - - function numericalSort ( a, b ) { - - return b[ 0 ] - a[ 0 ]; - - }; - - - // Rendering - - this.render = function ( scene, camera, renderTarget, forceClear ) { - - if ( camera instanceof THREE.Camera === false ) { - - THREE.onerror( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; - - } - - var i, il, - - webglObject, object, - renderList, - - lights = scene.__lights, - fog = scene.fog; - - // reset caching for this frame - - _currentMaterialId = -1; - _lightsNeedUpdate = true; - - // update scene graph - - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - - // update camera matrices and frustum - - if ( camera.parent === undefined ) camera.updateMatrixWorld(); - - camera.matrixWorldInverse.getInverse( camera.matrixWorld ); - - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); - - // update WebGL objects - - if ( this.autoUpdateObjects ) this.initWebGLObjects( scene ); - - // custom render plugins (pre pass) - - renderPlugins( this.renderPluginsPre, scene, camera ); - - // - - _this.info.render.calls = 0; - _this.info.render.vertices = 0; - _this.info.render.faces = 0; - _this.info.render.points = 0; - - this.setRenderTarget( renderTarget ); - - if ( this.autoClear || forceClear ) { - - this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); - - } - - // set matrices for regular objects (frustum culled) - - renderList = scene.__webglObjects; - - for ( i = 0, il = renderList.length; i < il; i ++ ) { - - webglObject = renderList[ i ]; - object = webglObject.object; - - webglObject.id = i; - webglObject.render = false; - - if ( object.visible ) { - - if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { - - setupMatrices( object, camera ); - - unrollBufferMaterial( webglObject ); - - webglObject.render = true; - - if ( this.sortObjects === true ) { - - if ( object.renderDepth !== null ) { - - webglObject.z = object.renderDepth; - - } else { - - _vector3.setFromMatrixPosition( object.matrixWorld ); - _vector3.applyProjection( _projScreenMatrix ); - - webglObject.z = _vector3.z; - - } - - } - - } - - } - - } - - if ( this.sortObjects ) { - - renderList.sort( painterSortStable ); - - } - - // set matrices for immediate objects - - renderList = scene.__webglObjectsImmediate; - - for ( i = 0, il = renderList.length; i < il; i ++ ) { - - webglObject = renderList[ i ]; - object = webglObject.object; - - if ( object.visible ) { - - setupMatrices( object, camera ); - - unrollImmediateBufferMaterial( webglObject ); - - } - - } - - if ( scene.overrideMaterial ) { - - var material = scene.overrideMaterial; - - this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); - this.setDepthTest( material.depthTest ); - this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - - renderObjects( scene.__webglObjects, false, "", camera, lights, fog, true, material ); - renderObjectsImmediate( scene.__webglObjectsImmediate, "", camera, lights, fog, false, material ); - - } else { - - var material = null; - - // opaque pass (front-to-back order) - - this.setBlending( THREE.NoBlending ); - - renderObjects( scene.__webglObjects, true, "opaque", camera, lights, fog, false, material ); - renderObjectsImmediate( scene.__webglObjectsImmediate, "opaque", camera, lights, fog, false, material ); - - // transparent pass (back-to-front order) - - renderObjects( scene.__webglObjects, false, "transparent", camera, lights, fog, true, material ); - renderObjectsImmediate( scene.__webglObjectsImmediate, "transparent", camera, lights, fog, true, material ); - - } - - // custom render plugins (post pass) - - renderPlugins( this.renderPluginsPost, scene, camera ); - - - // Generate mipmap if we're using any kind of mipmap filtering - - if ( renderTarget && renderTarget.generateMipmaps && - renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter && - THREE.isPowerOfTwo( renderTarget.width ) && THREE.isPowerOfTwo( renderTarget.height ) ) { - - updateRenderTargetMipmap( renderTarget ); - - } - - // Ensure depth buffer writing is enabled so it can be cleared on next render - - this.setDepthTest( true ); - this.setDepthWrite( true ); - - // _gl.finish(); - - }; - - function renderPlugins( plugins, scene, camera ) { - - if ( ! plugins.length ) return; - - for ( var i = 0, il = plugins.length; i < il; i ++ ) { - - // reset state for plugin (to start from clean slate) - - _currentProgram = null; - _currentCamera = null; - - _oldBlending = -1; - _oldDepthTest = -1; - _oldDepthWrite = -1; - _oldDoubleSided = -1; - _oldFlipSided = -1; - _currentGeometryGroupHash = -1; - _currentMaterialId = -1; - - _lightsNeedUpdate = true; - - plugins[ i ].render( scene, camera, _currentWidth, _currentHeight ); - - // reset state after plugin (anything could have changed) - - _currentProgram = null; - _currentCamera = null; - - _oldBlending = -1; - _oldDepthTest = -1; - _oldDepthWrite = -1; - _oldDoubleSided = -1; - _oldFlipSided = -1; - _currentGeometryGroupHash = -1; - _currentMaterialId = -1; - - _lightsNeedUpdate = true; - - } - - }; - - function renderObjects( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) { - - var webglObject, object, buffer, material, start, end, delta; - - if ( reverse ) { - - start = renderList.length - 1; - end = -1; - delta = -1; - - } else { - - start = 0; - end = renderList.length; - delta = 1; - } - - for ( var i = start; i !== end; i += delta ) { - - webglObject = renderList[ i ]; - - if ( webglObject.render ) { - - object = webglObject.object; - buffer = webglObject.buffer; - - if ( overrideMaterial ) { - - material = overrideMaterial; - - } else { - - material = webglObject[ materialType ]; - - if ( ! material ) continue; - - if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); - - _this.setDepthTest( material.depthTest ); - _this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - - } - - _this.setMaterialFaces( material ); - - if ( buffer instanceof THREE.BufferGeometry ) { - - _this.renderBufferDirect( camera, lights, fog, material, buffer, object ); - - } else { - - _this.renderBuffer( camera, lights, fog, material, buffer, object ); - - } - - } - - } - - }; - - function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) { - - var webglObject, object, material, program; - - for ( var i = 0, il = renderList.length; i < il; i ++ ) { - - webglObject = renderList[ i ]; - object = webglObject.object; - - if ( object.visible ) { - - if ( overrideMaterial ) { - - material = overrideMaterial; - - } else { - - material = webglObject[ materialType ]; - - if ( ! material ) continue; - - if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); - - _this.setDepthTest( material.depthTest ); - _this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - - } - - _this.renderImmediateObject( camera, lights, fog, material, object ); - - } - - } - - }; - - this.renderImmediateObject = function ( camera, lights, fog, material, object ) { - - var program = setProgram( camera, lights, fog, material, object ); - - _currentGeometryGroupHash = -1; - - _this.setMaterialFaces( material ); - - if ( object.immediateRenderCallback ) { - - object.immediateRenderCallback( program, _gl, _frustum ); - - } else { - - object.render( function( object ) { _this.renderBufferImmediate( object, program, material ); } ); - - } - - }; - - function unrollImmediateBufferMaterial ( globject ) { - - var object = globject.object, - material = object.material; - - if ( material.transparent ) { - - globject.transparent = material; - globject.opaque = null; - - } else { - - globject.opaque = material; - globject.transparent = null; - - } - - }; - - function unrollBufferMaterial ( globject ) { - - var object = globject.object; - var buffer = globject.buffer; - - var geometry = object.geometry; - var material = object.material; - - if ( material instanceof THREE.MeshFaceMaterial ) { - - var materialIndex = geometry instanceof THREE.BufferGeometry ? 0 : buffer.materialIndex; - - material = material.materials[ materialIndex ]; - - if ( material.transparent ) { - - globject.transparent = material; - globject.opaque = null; - - } else { - - globject.opaque = material; - globject.transparent = null; - - } - - } else { - - if ( material ) { - - if ( material.transparent ) { - - globject.transparent = material; - globject.opaque = null; - - } else { - - globject.opaque = material; - globject.transparent = null; - - } - - } - - } - - }; - - // Objects refresh - - this.initWebGLObjects = function ( scene ) { - - if ( !scene.__webglObjects ) { - - scene.__webglObjects = []; - scene.__webglObjectsImmediate = []; - scene.__webglSprites = []; - scene.__webglFlares = []; - - } - - while ( scene.__objectsAdded.length ) { - - addObject( scene.__objectsAdded[ 0 ], scene ); - scene.__objectsAdded.splice( 0, 1 ); - - } - - while ( scene.__objectsRemoved.length ) { - - removeObject( scene.__objectsRemoved[ 0 ], scene ); - scene.__objectsRemoved.splice( 0, 1 ); - - } - - // update must be called after objects adding / removal - - for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) { - - var object = scene.__webglObjects[ o ].object; - - // TODO: Remove this hack (WebGLRenderer refactoring) - - if ( object.__webglInit === undefined ) { - - if ( object.__webglActive !== undefined ) { - - removeObject( object, scene ); - - } - - addObject( object, scene ); - - } - - updateObject( object ); - - } - - }; - - // Objects adding - - function addObject( object, scene ) { - - var g, geometry, material, geometryGroup; - - if ( object.__webglInit === undefined ) { - - object.__webglInit = true; - - object._modelViewMatrix = new THREE.Matrix4(); - object._normalMatrix = new THREE.Matrix3(); - - if ( object.geometry !== undefined && object.geometry.__webglInit === undefined ) { - - object.geometry.__webglInit = true; - object.geometry.addEventListener( 'dispose', onGeometryDispose ); - - } - - geometry = object.geometry; - - if ( geometry === undefined ) { - - // fail silently for now - - } else if ( geometry instanceof THREE.BufferGeometry ) { - - initDirectBuffers( geometry ); - - } else if ( object instanceof THREE.Mesh ) { - - material = object.material; - - if ( geometry.geometryGroups === undefined ) { - - geometry.makeGroups( material instanceof THREE.MeshFaceMaterial ); - - } - - // create separate VBOs per geometry chunk - - for ( g in geometry.geometryGroups ) { - - geometryGroup = geometry.geometryGroups[ g ]; - - // initialise VBO on the first access - - if ( ! geometryGroup.__webglVertexBuffer ) { - - createMeshBuffers( geometryGroup ); - initMeshBuffers( geometryGroup, object ); - - geometry.verticesNeedUpdate = true; - geometry.morphTargetsNeedUpdate = true; - geometry.elementsNeedUpdate = true; - geometry.uvsNeedUpdate = true; - geometry.normalsNeedUpdate = true; - geometry.tangentsNeedUpdate = true; - - geometry.colorsNeedUpdate = true; - - } - - } - - } else if ( object instanceof THREE.Line ) { - - if ( ! geometry.__webglVertexBuffer ) { - - createLineBuffers( geometry ); - initLineBuffers( geometry, object ); - - geometry.verticesNeedUpdate = true; - geometry.colorsNeedUpdate = true; - geometry.lineDistancesNeedUpdate = true; - - } - - } else if ( object instanceof THREE.ParticleSystem ) { - - if ( ! geometry.__webglVertexBuffer ) { - - createParticleBuffers( geometry ); - initParticleBuffers( geometry, object ); - - geometry.verticesNeedUpdate = true; - geometry.colorsNeedUpdate = true; - - } - - } - - } - - if ( object.__webglActive === undefined ) { - - if ( object instanceof THREE.Mesh ) { - - geometry = object.geometry; - - if ( geometry instanceof THREE.BufferGeometry ) { - - addBuffer( scene.__webglObjects, geometry, object ); - - } else if ( geometry instanceof THREE.Geometry ) { - - for ( g in geometry.geometryGroups ) { - - geometryGroup = geometry.geometryGroups[ g ]; - - addBuffer( scene.__webglObjects, geometryGroup, object ); - - } - - } - - } else if ( object instanceof THREE.Line || - object instanceof THREE.ParticleSystem ) { - - geometry = object.geometry; - addBuffer( scene.__webglObjects, geometry, object ); - - } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { - - addBufferImmediate( scene.__webglObjectsImmediate, object ); - - } else if ( object instanceof THREE.Sprite ) { - - scene.__webglSprites.push( object ); - - } else if ( object instanceof THREE.LensFlare ) { - - scene.__webglFlares.push( object ); - - } - - object.__webglActive = true; - - } - - }; - - function addBuffer( objlist, buffer, object ) { - - objlist.push( - { - id: null, - buffer: buffer, - object: object, - opaque: null, - transparent: null, - z: 0 - } - ); - - }; - - function addBufferImmediate( objlist, object ) { - - objlist.push( - { - id: null, - object: object, - opaque: null, - transparent: null, - z: 0 - } - ); - - }; - - // Objects updates - - function updateObject( object ) { - - var geometry = object.geometry, - geometryGroup, customAttributesDirty, material; - - if ( geometry instanceof THREE.BufferGeometry ) { - - setDirectBuffers( geometry, _gl.DYNAMIC_DRAW ); - - } else if ( object instanceof THREE.Mesh ) { - - // check all geometry groups - - for( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) { - - geometryGroup = geometry.geometryGroupsList[ i ]; - - material = getBufferMaterial( object, geometryGroup ); - - if ( geometry.buffersNeedUpdate ) { - - initMeshBuffers( geometryGroup, object ); - - } - - customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); - - if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate || - geometry.uvsNeedUpdate || geometry.normalsNeedUpdate || - geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) { - - setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, !geometry.dynamic, material ); - - } - - } - - geometry.verticesNeedUpdate = false; - geometry.morphTargetsNeedUpdate = false; - geometry.elementsNeedUpdate = false; - geometry.uvsNeedUpdate = false; - geometry.normalsNeedUpdate = false; - geometry.colorsNeedUpdate = false; - geometry.tangentsNeedUpdate = false; - - geometry.buffersNeedUpdate = false; - - material.attributes && clearCustomAttributes( material ); - - } else if ( object instanceof THREE.Line ) { - - material = getBufferMaterial( object, geometry ); - - customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); - - if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) { - - setLineBuffers( geometry, _gl.DYNAMIC_DRAW ); - - } - - geometry.verticesNeedUpdate = false; - geometry.colorsNeedUpdate = false; - geometry.lineDistancesNeedUpdate = false; - - material.attributes && clearCustomAttributes( material ); - - - } else if ( object instanceof THREE.ParticleSystem ) { - - material = getBufferMaterial( object, geometry ); - - customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); - - if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || object.sortParticles || customAttributesDirty ) { - - setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object ); - - } - - geometry.verticesNeedUpdate = false; - geometry.colorsNeedUpdate = false; - - material.attributes && clearCustomAttributes( material ); - - } - - }; - - // Objects updates - custom attributes check - - function areCustomAttributesDirty( material ) { - - for ( var a in material.attributes ) { - - if ( material.attributes[ a ].needsUpdate ) return true; - - } - - return false; - - }; - - function clearCustomAttributes( material ) { - - for ( var a in material.attributes ) { - - material.attributes[ a ].needsUpdate = false; - - } - - }; - - // Objects removal - - function removeObject( object, scene ) { - - if ( object instanceof THREE.Mesh || - object instanceof THREE.ParticleSystem || - object instanceof THREE.Line ) { - - removeInstances( scene.__webglObjects, object ); - - } else if ( object instanceof THREE.Sprite ) { - - removeInstancesDirect( scene.__webglSprites, object ); - - } else if ( object instanceof THREE.LensFlare ) { - - removeInstancesDirect( scene.__webglFlares, object ); - - } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { - - removeInstances( scene.__webglObjectsImmediate, object ); - - } - - delete object.__webglActive; - - }; - - function removeInstances( objlist, object ) { - - for ( var o = objlist.length - 1; o >= 0; o -- ) { - - if ( objlist[ o ].object === object ) { - - objlist.splice( o, 1 ); - - } - - } - - }; - - function removeInstancesDirect( objlist, object ) { - - for ( var o = objlist.length - 1; o >= 0; o -- ) { - - if ( objlist[ o ] === object ) { - - objlist.splice( o, 1 ); - - } - - } - - }; - - // Materials - - this.initMaterial = function ( material, lights, fog, object ) { - - material.addEventListener( 'dispose', onMaterialDispose ); - - var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID; - - if ( material instanceof THREE.MeshDepthMaterial ) { - - shaderID = 'depth'; - - } else if ( material instanceof THREE.MeshNormalMaterial ) { - - shaderID = 'normal'; - - } else if ( material instanceof THREE.MeshBasicMaterial ) { - - shaderID = 'basic'; - - } else if ( material instanceof THREE.MeshLambertMaterial ) { - - shaderID = 'lambert'; - - } else if ( material instanceof THREE.MeshPhongMaterial ) { - - shaderID = 'phong'; - - } else if ( material instanceof THREE.MeshPhysicalMaterial ) { - - shaderID = 'physical'; - - } else if ( material instanceof THREE.LineBasicMaterial ) { - - shaderID = 'basic'; - - } else if ( material instanceof THREE.LineDashedMaterial ) { - - shaderID = 'dashed'; - - } else if ( material instanceof THREE.ParticleSystemMaterial ) { - - shaderID = 'particle_basic'; - - } - - if ( shaderID && THREE.ShaderLib[ shaderID ] ) { - - setMaterialShaders( material, THREE.ShaderLib[ shaderID ] ); - - } - - if( ! shaderID ) { - shaderID = material.shaderID; - } - - // heuristics to create shader parameters according to lights in the scene - // (not to blow over maxLights budget) - - maxLightCount = allocateLights( lights ); - - maxShadows = allocateShadows( lights ); - - maxBones = allocateBones( object ); - - parameters = { - - map: !!material.map, - opacityMap: !!material.opacityMap, - envMap: !!material.envMap, - diffuseEnvMap: !!material.diffuseEnvMap, - lightMap: !!material.lightMap, - emissiveMap: !!material.emissiveMap, - bumpMap: !!material.bumpMap, - normalMap: !!material.normalMap, - specularMap: !!material.specularMap, - reflectivityMap: !!material.reflectivityMap, - roughnessMap: !!material.roughnessMap, - translucencyMap: !!material.translucencyMap, - metallicMap: !!material.metallicMap, - falloffMap: !!material.falloffMap, - - clearCoat: (( material.clearCoat !== undefined )&&( material.clearCoat !== 0 )), - - anisotropy: (( material.anisotropy !== undefined )&&( material.anisotropy !== 0 ))||( !! material.anisotropyMap ), - anisotropyMap: !! material.anisotropyMap, - anisotropyRotation: (( material.anisotropyRotation !== undefined )&&( material.anisotropyRotation !== 0 ))||( !! material.anisotropyRotationMap ), - anisotropyRotationMap: !! material.anisotropyRotationMap, - - vertexColors: material.vertexColors, - - fog: fog, - useFog: material.fog, - fogExp: fog instanceof THREE.FogExp2, - - sizeAttenuation: !! material.sizeAttenuation, - - skinning: material.skinning, - maxBones: maxBones, - useVertexTexture: _supportsBoneTextures && object && object.useVertexTexture, - - morphTargets: material.morphTargets, - morphNormals: material.morphNormals, - maxMorphTargets: this.maxMorphTargets, - maxMorphNormals: this.maxMorphNormals, - - maxDirLights: maxLightCount.directional, - maxPointLights: maxLightCount.point, - maxSpotLights: maxLightCount.spot, - maxHemiLights: maxLightCount.hemi, - maxAreaLights: maxLightCount.area, - - maxShadows: maxShadows, - shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow && maxShadows > 0, - shadowMapType: this.shadowMapType, - shadowMapDebug: this.shadowMapDebug, - shadowMapCascade: this.shadowMapCascade, - - translucency: material.translucency && ( material.translucency.getHex() > 0 ), - - alphaTest: material.alphaTest, - falloff: ( material.falloff || false ), - wrapAround: material.wrapAround, - doubleSided: material.side === THREE.DoubleSide, - flipSided: material.side === THREE.BackSide - - }; - - material.program = buildProgram( shaderID, material.fragmentShader, material.vertexShader, material.uniforms, material.attributes, material.defines, parameters, material.index0AttributeName ); - - var attributes = material.program.attributes; - - if ( material.morphTargets ) { - - material.numSupportedMorphTargets = 0; - - var id, base = "morphTarget"; - - for ( i = 0; i < this.maxMorphTargets; i ++ ) { - - id = base + i; - - if ( attributes[ id ] >= 0 ) { - - material.numSupportedMorphTargets ++; - - } - - } - - } - - if ( material.morphNormals ) { - - material.numSupportedMorphNormals = 0; - - var id, base = "morphNormal"; - - for ( i = 0; i < this.maxMorphNormals; i ++ ) { - - id = base + i; - - if ( attributes[ id ] >= 0 ) { - - material.numSupportedMorphNormals ++; - - } - - } - - } - - material.uniformsList = []; - - for ( u in material.uniforms ) { - - material.uniformsList.push( [ material.uniforms[ u ], u ] ); - - } - - }; - - function setMaterialShaders( material, shaders ) { - - material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms ); - material.vertexShader = shaders.vertexShader; - material.fragmentShader = shaders.fragmentShader; - - }; - - function setProgram( camera, lights, fog, material, object ) { - - _usedTextureUnits = 0; - - if ( material.needsUpdate ) { - - var oldProgram = material.program; - - _this.initMaterial( material, lights, fog, object ); - material.needsUpdate = false; - - if ( oldProgram ) deallocateMaterial( material, oldProgram ); - - - } - - if ( material.morphTargets ) { - - if ( ! object.__webglMorphTargetInfluences ) { - - object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets ); - - } - - } - - var refreshMaterial = false; - - var program = material.program, - p_uniforms = program.uniforms, - m_uniforms = material.uniforms; - - if ( program !== _currentProgram ) { - - _gl.useProgram( program ); - _currentProgram = program; - - refreshMaterial = true; - - } - - if ( material.id !== _currentMaterialId ) { - - _currentMaterialId = material.id; - refreshMaterial = true; - - } - - if ( refreshMaterial || camera !== _currentCamera ) { - - _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); - - if ( camera !== _currentCamera ) _currentCamera = camera; - - } - - // skinning uniforms must be set even if material didn't change - // auto-setting of texture unit for bone texture must go before other textures - // not sure why, but otherwise weird things happen - - if ( material.skinning ) { - - if ( _supportsBoneTextures && object.useVertexTexture ) { - - if ( p_uniforms.boneTexture !== null ) { - - var textureUnit = getTextureUnit(); - - _gl.uniform1i( p_uniforms.boneTexture, textureUnit ); - _this.setTexture( object.boneTexture, textureUnit ); - - } - - if ( p_uniforms.boneTextureWidth !== null ) { - - _gl.uniform1i( p_uniforms.boneTextureWidth, object.boneTextureWidth ); - - } - - if ( p_uniforms.boneTextureHeight !== null ) { - - _gl.uniform1i( p_uniforms.boneTextureHeight, object.boneTextureHeight ); - - } - - } else { - - if ( p_uniforms.boneGlobalMatrices !== null ) { - - _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices ); - - } - - } - - } - - if ( refreshMaterial ) { - - // refresh uniforms common to several materials - - if ( fog && material.fog ) { - - refreshUniformsFog( m_uniforms, fog ); - - } - - if ( material instanceof THREE.MeshPhongMaterial || - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.MeshPhysicalMaterial || - material.lights ) { - - if ( _lightsNeedUpdate ) { - - setupLights( program, lights ); - _lightsNeedUpdate = false; - - } - - refreshUniformsLights( m_uniforms, _lights ); - - } - - if ( material instanceof THREE.MeshBasicMaterial || - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.MeshPhysicalMaterial || - material instanceof THREE.MeshPhongMaterial ) { - - refreshUniformsCommon( m_uniforms, material ); - - } - - // refresh single material specific uniforms - - if ( material instanceof THREE.LineBasicMaterial ) { - - refreshUniformsLine( m_uniforms, material ); - - } else if ( material instanceof THREE.LineDashedMaterial ) { - - refreshUniformsLine( m_uniforms, material ); - refreshUniformsDash( m_uniforms, material ); - - } else if ( material instanceof THREE.ParticleSystemMaterial ) { - - refreshUniformsParticle( m_uniforms, material ); - - } else if ( material instanceof THREE.MeshPhongMaterial ) { - - refreshUniformsPhong( m_uniforms, material ); - - } else if ( material instanceof THREE.MeshPhysicalMaterial ) { - - refreshUniformsPhysical( m_uniforms, material ); - - } else if ( material instanceof THREE.MeshLambertMaterial ) { - - refreshUniformsLambert( m_uniforms, material ); - - } else if ( material instanceof THREE.MeshDepthMaterial ) { - - m_uniforms.mNear.value = camera.near; - m_uniforms.mFar.value = camera.far; - m_uniforms.opacity.value = material.opacity; - - } else if ( material instanceof THREE.MeshNormalMaterial ) { - - m_uniforms.opacity.value = material.opacity; - - } - - if ( object.receiveShadow && ! material._shadowPass ) { - - refreshUniformsShadow( m_uniforms, lights ); - - } - - // load common uniforms - - loadUniformsGeneric( program, material.uniformsList ); - - // load material specific uniforms - // (shader material also gets them for the sake of genericity) - - if ( material instanceof THREE.ShaderMaterial || - material instanceof THREE.MeshPhongMaterial || - material instanceof THREE.MeshPhysicalMaterial || - material.envMap || - material.diffuseEnvMap ) { - - if ( p_uniforms.cameraPosition !== null ) { - - _vector3.setFromMatrixPosition( camera.matrixWorld ); - _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z ); - - } - - } - - if ( material instanceof THREE.MeshPhongMaterial || - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.MeshPhysicalMaterial || - material instanceof THREE.ShaderMaterial || - material.skinning ) { - - if ( p_uniforms.viewMatrix !== null ) { - - _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements ); - - } - - } - - } - - loadUniformsMatrices( p_uniforms, object ); - - if ( p_uniforms.modelMatrix !== null ) { - - _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements ); - - } - - return program; - - }; - - // Uniforms (refresh uniforms objects) - - function refreshUniformsCommon ( uniforms, material ) { - - uniforms.opacity.value = material.opacity; - - uniforms.diffuse.value = material.color; - - uniforms.map.value = material.map; - uniforms.lightMap.value = material.lightMap; - uniforms.emissiveMap.value = material.emissiveMap; - - if ( material.bumpMap ) { - - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; - - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - - } - - if ( material.map ) { - - var map = material.map; - uniforms.offsetRepeat.value.set( map.offset.x, map.offset.y, map.repeat.x, map.repeat.y ); - uniforms.gainBrightness.value.set( map.gainPivot, map.gain, map.brightness, map.invert ? -1.0 : 1.0 ); - - } - - if ( material.specularMap ) { - - var specularMap = material.specularMap; - uniforms.specularMap.value = specularMap; - uniforms.specularOffsetRepeat.value.set( specularMap.offset.x, specularMap.offset.y, specularMap.repeat.x, specularMap.repeat.y ); - uniforms.specularGainBrightness.value.set( specularMap.gainPivot, specularMap.gain, specularMap.brightness, specularMap.invert ? -1.0 : 1.0 ); - - } - - if ( material.opacityMap ) { - - var opacityMap = material.opacityMap; - uniforms.opacityMap.value = opacityMap; - uniforms.opacityOffsetRepeat.value.set( opacityMap.offset.x, opacityMap.offset.y, opacityMap.repeat.x, opacityMap.repeat.y ); - uniforms.opacityGainBrightness.value.set( opacityMap.gainPivot, opacityMap.gain, opacityMap.brightness, opacityMap.invert ? -1.0 : 1.0 ); - - } - - if ( material.bumpMap ) { - - var bumpMap = material.bumpMap; - uniforms.bumpOffsetRepeat.value.set( bumpMap.offset.x, bumpMap.offset.y, bumpMap.repeat.x, bumpMap.repeat.y ); - //uniforms.bumpGainBrightness.value.set( bumpMap.gainPivot, bumpMap.gain, bumpMap.brightness, 1.0 ); - - } - - if ( material.normalMap ) { - - var normalMap = material.normalMap; - uniforms.normalOffsetRepeat.value.set( normalMap.offset.x, normalMap.offset.y, normalMap.repeat.x, normalMap.repeat.y ); - //uniforms.normalGainBrightness.value.set( normalMap.gainPivot, normalMap.gain, normalMap.brightness, 1.0 ); - - } - - if ( material.anisotropyMap ) { - - var anisotropyMap = material.anisotropyMap; - uniforms.anisotropyOffsetRepeat.value.set( anisotropyMap.offset.x, anisotropyMap.offset.y, anisotropyMap.repeat.x, anisotropyMap.repeat.y ); - uniforms.anisotropyGainBrightness.value.set( anisotropyMap.gainPivot, anisotropyMap.gain, anisotropyMap.brightness, anisotropyMap.invert ? -1.0 : 1.0 ); - - } - - if ( material.anisotropyRotationMap ) { - - var anisotropyRotationMap = material.anisotropyRotationMap; - uniforms.anisotropyRotationOffsetRepeat.value.set( anisotropyRotationMap.offset.x, anisotropyRotationMap.offset.y, anisotropyRotationMap.repeat.x, anisotropyRotationMap.repeat.y ); - uniforms.anisotropyRotationGainBrightness.value.set( anisotropyRotationMap.gainPivot, anisotropyRotationMap.gain, anisotropyRotationMap.brightness, anisotropyRotationMap.invert ? -1.0 : 1.0 ); - - } - - if ( material.roughnessMap ) { - - var roughnessMap = material.roughnessMap; - uniforms.roughnessOffsetRepeat.value.set( roughnessMap.offset.x, roughnessMap.offset.y, roughnessMap.repeat.x, roughnessMap.repeat.y ); - uniforms.roughnessGainBrightness.value.set( roughnessMap.gainPivot, roughnessMap.gain, roughnessMap.brightness, roughnessMap.invert ? -1.0 : 1.0 ); - - } - - if ( material.metallicMap ) { - - var metallicMap = material.metallicMap; - uniforms.metallicOffsetRepeat.value.set( metallicMap.offset.x, metallicMap.offset.y, metallicMap.repeat.x, metallicMap.repeat.y ); - uniforms.metallicGainBrightness.value.set( metallicMap.gainPivot, metallicMap.gain, metallicMap.brightness, metallicMap.invert ? -1.0 : 1.0 ); - - } - - if ( material.translucencyMap ) { - - var translucencyMap = material.translucencyMap; - uniforms.translucencyMap.value = translucencyMap; - //uniforms.translucencyOffsetRepeat.value.set( translucencyMap.offset.x, translucencyMap.offset.y, translucencyMap.repeat.x, translucencyMap.repeat.y ); - //uniforms.translucencyGainBrightness.value.set( translucencyMap.gainPivot, translucencyMap.gain, translucencyMap.brightness, 1.0 ); - - } - uniforms.envMap.value = material.envMap; - uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1; - uniforms.envEncoding.value = ( material.envMap ) ? material.envMap.encoding : 0; - uniforms.diffuseEnvMap.value = material.diffuseEnvMap; - uniforms.diffuseEnvEncoding.value = ( material.diffuseEnvMap ) ? material.diffuseEnvMap.encoding : 0; - - uniforms.reflectivity.value = material.reflectivity; - - uniforms.refractionRatio.value = material.refractionRatio; - uniforms.combine.value = material.combine; - uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping; - - }; - - function refreshUniformsLine ( uniforms, material ) { - - uniforms.diffuse.value = material.color; - uniforms.opacity.value = material.opacity; - - }; - - function refreshUniformsDash ( uniforms, material ) { - - uniforms.dashSize.value = material.dashSize; - uniforms.totalSize.value = material.dashSize + material.gapSize; - uniforms.scale.value = material.scale; - - }; - - function refreshUniformsParticle ( uniforms, material ) { - - uniforms.psColor.value = material.color; - uniforms.opacity.value = material.opacity; - uniforms.size.value = material.size; - uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this. - - uniforms.map.value = material.map; - - }; - - function refreshUniformsFog ( uniforms, fog ) { - - uniforms.fogColor.value = fog.color; - - if ( fog instanceof THREE.Fog ) { - - uniforms.fogNear.value = fog.near; - uniforms.fogFar.value = fog.far; - - } else if ( fog instanceof THREE.FogExp2 ) { - - uniforms.fogDensity.value = fog.density; - - } - - }; - - function refreshUniformsPhong ( uniforms, material ) { - - uniforms.opacityMap.value = material.opacityMap; - - uniforms.shininess.value = material.shininess; - - uniforms.ambient.value = material.ambient; - uniforms.emissive.value = material.emissive; - uniforms.specular.value = material.specular; - - if ( material.wrapAround ) { - - uniforms.wrapRGB.value.copy( material.wrapRGB ); - - } - - }; - - function refreshUniformsPhysical ( uniforms, material ) { - - uniforms.opacityMap.value = material.opacityMap; - - uniforms.falloffBlendParams.value = material.falloffBlendParams; - uniforms.falloffMap.value = material.falloffMap; - - uniforms.roughness.value = material.roughness; - uniforms.metallic.value = material.metallic; - - uniforms.clearCoat.value = material.clearCoat; - uniforms.clearCoatRoughness.value = material.clearCoatRoughness; - - uniforms.roughnessMap.value = material.roughnessMap; - uniforms.metallicMap.value = material.metallicMap; - - uniforms.translucencyMap.value = material.translucencyMap; - uniforms.translucencyNormalAlpha.value = material.translucencyNormalAlpha; - uniforms.translucencyNormalPower.value = material.translucencyNormalPower; - uniforms.translucencyViewAlpha.value = material.translucencyViewAlpha; - uniforms.translucencyViewPower.value = material.translucencyViewPower; - - uniforms.anisotropyMap.value = material.anisotropyMap; - uniforms.anisotropy.value = material.anisotropy; - uniforms.anisotropyRotation.value = material.anisotropyRotation; - uniforms.anisotropyRotationMap.value = material.anisotropyRotationMap; - - uniforms.ambient.value = material.ambient; - uniforms.emissive.value = material.emissive; - uniforms.falloffColor.value = material.falloffColor; - uniforms.specular.value = material.specular; - uniforms.translucency.value = material.translucency; - - }; - - function refreshUniformsLambert ( uniforms, material ) { - - uniforms.ambient.value = material.ambient; - uniforms.emissive.value = material.emissive; - - if ( material.wrapAround ) { - - uniforms.wrapRGB.value.copy( material.wrapRGB ); - - } - - }; - - function refreshUniformsLights ( uniforms, lights ) { - - uniforms.ambientLightColor.value = lights.ambient; - - uniforms.directionalLightColor.value = lights.directional.colors; - uniforms.directionalLightDirection.value = lights.directional.positions; - - uniforms.pointLightColor.value = lights.point.colors; - uniforms.pointLightPosition.value = lights.point.positions; - uniforms.pointLightDistance.value = lights.point.distances; - uniforms.pointLightDecayExponent.value = lights.point.decayExponents; - - uniforms.spotLightColor.value = lights.spot.colors; - uniforms.spotLightPosition.value = lights.spot.positions; - uniforms.spotLightDistance.value = lights.spot.distances; - uniforms.spotLightDecayExponent.value = lights.spot.decayExponents; - uniforms.spotLightDirection.value = lights.spot.directions; - uniforms.spotLightAngleCos.value = lights.spot.anglesCos; - uniforms.spotLightExponent.value = lights.spot.exponents; - - uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; - uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; - uniforms.hemisphereLightDirection.value = lights.hemi.positions; - - uniforms.areaLightColor.value = lights.area.colors; - uniforms.areaLightPosition.value = lights.area.positions; - uniforms.areaLightDistance.value = lights.area.distances; - uniforms.areaLightDecayExponent.value = lights.area.decayExponents; - uniforms.areaLightWidth.value = lights.area.widths; - uniforms.areaLightHeight.value = lights.area.heights; - - }; - - function refreshUniformsShadow ( uniforms, lights ) { - - if ( uniforms.shadowMatrix ) { - - var j = 0; - - for ( var i = 0, il = lights.length; i < il; i ++ ) { - - var light = lights[ i ]; - - if ( ! light.castShadow ) continue; - - if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) { - - uniforms.shadowMap.value[ j ] = light.shadowMap; - uniforms.shadowMapSize.value[ j ] = light.shadowMapSize; - - uniforms.shadowMatrix.value[ j ] = light.shadowMatrix; - - uniforms.shadowDarkness.value[ j ] = light.shadowDarkness; - uniforms.shadowBias.value[ j ] = light.shadowBias; - - j ++; - - } - - } - - } - - }; - - // Uniforms (load to GPU) - - function loadUniformsMatrices ( uniforms, object ) { - - _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements ); - - if ( uniforms.normalMatrix ) { - - _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements ); - - } - - }; - - function getTextureUnit() { - - var textureUnit = _usedTextureUnits; - - if ( textureUnit >= _maxTextures ) { - - THREE.onwarning( "WebGLRenderer: trying to use " + textureUnit + " texture units while this GPU supports only " + _maxTextures ); - - } - - _usedTextureUnits += 1; - - return textureUnit; - - }; - - function loadUniformsGeneric ( program, uniforms ) { - - var uniform, value, type, location, texture, textureUnit, i, il, j, jl, offset; - - for ( j = 0, jl = uniforms.length; j < jl; j ++ ) { - - location = program.uniforms[ uniforms[ j ][ 1 ] ]; - if ( !location ) continue; - - uniform = uniforms[ j ][ 0 ]; - - type = uniform.type; - value = uniform.value; - - if ( type === "i" ) { // single integer - - _gl.uniform1i( location, value ); - - } else if ( type === "f" ) { // single float - - _gl.uniform1f( location, value ); - - } else if ( type === "v2" ) { // single THREE.Vector2 - - _gl.uniform2f( location, value.x, value.y ); - - } else if ( type === "v3" ) { // single THREE.Vector3 - - _gl.uniform3f( location, value.x, value.y, value.z ); - - } else if ( type === "v4" ) { // single THREE.Vector4 - - _gl.uniform4f( location, value.x, value.y, value.z, value.w ); - - } else if ( type === "c" ) { // single THREE.Color - - _gl.uniform3f( location, value.r, value.g, value.b ); - - } else if ( type === "iv1" ) { // flat array of integers (JS or typed array) - - _gl.uniform1iv( location, value ); - - } else if ( type === "iv" ) { // flat array of integers with 3 x N size (JS or typed array) - - _gl.uniform3iv( location, value ); - - } else if ( type === "fv1" ) { // flat array of floats (JS or typed array) - - _gl.uniform1fv( location, value ); - - } else if ( type === "fv" ) { // flat array of floats with 3 x N size (JS or typed array) - - _gl.uniform3fv( location, value ); - - } else if ( type === "v2v" ) { // array of THREE.Vector2 - - if ( uniform._array === undefined ) { - - uniform._array = new Float32Array( 2 * value.length ); - - } - - for ( i = 0, il = value.length; i < il; i ++ ) { - - offset = i * 2; - - uniform._array[ offset ] = value[ i ].x; - uniform._array[ offset + 1 ] = value[ i ].y; - - } - - _gl.uniform2fv( location, uniform._array ); - - } else if ( type === "v3v" ) { // array of THREE.Vector3 - - if ( uniform._array === undefined ) { - - uniform._array = new Float32Array( 3 * value.length ); - - } - - for ( i = 0, il = value.length; i < il; i ++ ) { - - offset = i * 3; - - uniform._array[ offset ] = value[ i ].x; - uniform._array[ offset + 1 ] = value[ i ].y; - uniform._array[ offset + 2 ] = value[ i ].z; - - } - - _gl.uniform3fv( location, uniform._array ); - - } else if ( type === "v4v" ) { // array of THREE.Vector4 - - if ( uniform._array === undefined ) { - - uniform._array = new Float32Array( 4 * value.length ); - - } - - for ( i = 0, il = value.length; i < il; i ++ ) { - - offset = i * 4; - - uniform._array[ offset ] = value[ i ].x; - uniform._array[ offset + 1 ] = value[ i ].y; - uniform._array[ offset + 2 ] = value[ i ].z; - uniform._array[ offset + 3 ] = value[ i ].w; - - } - - _gl.uniform4fv( location, uniform._array ); - - } else if ( type === "m4") { // single THREE.Matrix4 - - if ( uniform._array === undefined ) { - - uniform._array = new Float32Array( 16 ); - - } - - value.flattenToArray( uniform._array ); - _gl.uniformMatrix4fv( location, false, uniform._array ); - - } else if ( type === "m4v" ) { // array of THREE.Matrix4 - - if ( uniform._array === undefined ) { - - uniform._array = new Float32Array( 16 * value.length ); - - } - - for ( i = 0, il = value.length; i < il; i ++ ) { - - value[ i ].flattenToArrayOffset( uniform._array, i * 16 ); - - } - - _gl.uniformMatrix4fv( location, false, uniform._array ); - - } else if ( type === "t" ) { // single THREE.Texture (2d or cube) - - texture = value; - textureUnit = getTextureUnit(); - - _gl.uniform1i( location, textureUnit ); - - if ( !texture ) continue; - - if ( texture.image instanceof Array && texture.image.length === 6 ) { - - setCubeTexture( texture, textureUnit ); - - } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { - - setCubeTextureDynamic( texture, textureUnit ); - - } else { - - _this.setTexture( texture, textureUnit ); - - } - - } else if ( type === "tv" ) { // array of THREE.Texture (2d) - - if ( uniform._array === undefined ) { - - uniform._array = []; - - } - - for( i = 0, il = uniform.value.length; i < il; i ++ ) { - - uniform._array[ i ] = getTextureUnit(); - - } - - _gl.uniform1iv( location, uniform._array ); - - for( i = 0, il = uniform.value.length; i < il; i ++ ) { - - texture = uniform.value[ i ]; - textureUnit = uniform._array[ i ]; - - if ( !texture ) continue; - - _this.setTexture( texture, textureUnit ); - - } - - } else { - - THREE.onwarning( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); - - } - - } - - }; - - function setupMatrices ( object, camera ) { - - object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object._normalMatrix.getNormalMatrix( object._modelViewMatrix ); - - }; - - // - - - function setColorLinear( array, offset, color, intensity ) { - - array[ offset ] = color.r * intensity; - array[ offset + 1 ] = color.g * intensity; - array[ offset + 2 ] = color.b * intensity; - - }; - - function setupLights ( program, lights ) { - - var l, ll, light, n, - r = 0, g = 0, b = 0, - color, skyColor, groundColor, - intensity, intensitySq, - position, - distance, - - zlights = _lights, - - dirColors = zlights.directional.colors, - dirPositions = zlights.directional.positions, - - pointColors = zlights.point.colors, - pointPositions = zlights.point.positions, - pointDistances = zlights.point.distances, - pointDecayExponents = zlights.point.decayExponents, - - spotColors = zlights.spot.colors, - spotPositions = zlights.spot.positions, - spotDistances = zlights.spot.distances, - spotDecayExponents = zlights.spot.decayExponents, - spotDirections = zlights.spot.directions, - spotAnglesCos = zlights.spot.anglesCos, - spotExponents = zlights.spot.exponents, - - hemiSkyColors = zlights.hemi.skyColors, - hemiGroundColors = zlights.hemi.groundColors, - hemiPositions = zlights.hemi.positions, - - areaColors = zlights.area.colors, - areaPositions = zlights.area.positions, - areaDistances = zlights.area.distances, - areaDecayExponents = zlights.area.decayExponents, - areaWidths = zlights.area.widths, - areaHeights = zlights.area.heights, - - dirLength = 0, - pointLength = 0, - spotLength = 0, - hemiLength = 0, - areaLength = 0, - - dirCount = 0, - pointCount = 0, - spotCount = 0, - hemiCount = 0, - areaCount = 0, - - dirOffset = 0, - pointOffset = 0, - spotOffset = 0, - hemiOffset = 0, - areaOffset = 0; - - for ( l = 0, ll = lights.length; l < ll; l ++ ) { - - light = lights[ l ]; - - if ( light.onlyShadow ) continue; - - color = light.color; - intensity = light.intensity; - distance = light.distance; - - if ( light instanceof THREE.AmbientLight ) { - - if ( ! light.visible ) continue; - - r += color.r; - g += color.g; - b += color.b; - - } else if ( light instanceof THREE.DirectionalLight ) { - - dirCount += 1; - - if ( ! light.visible ) continue; - - _direction.setFromMatrixPosition( light.matrixWorld ); - _vector3.setFromMatrixPosition( light.target.matrixWorld ); - _direction.sub( _vector3 ); - _direction.normalize(); - - // skip lights with undefined direction - // these create troubles in OpenGL (making pixel black) - - if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; - - dirOffset = dirLength * 3; - - dirPositions[ dirOffset ] = _direction.x; - dirPositions[ dirOffset + 1 ] = _direction.y; - dirPositions[ dirOffset + 2 ] = _direction.z; - - - setColorLinear( dirColors, dirOffset, color, intensity ); - - dirLength += 1; - - } else if ( light instanceof THREE.PointLight ) { - - pointCount += 1; - - if ( ! light.visible ) continue; - - pointOffset = pointLength * 3; - - setColorLinear( pointColors, pointOffset, color, intensity ); - - _vector3.setFromMatrixPosition( light.matrixWorld ); - - pointPositions[ pointOffset ] = _vector3.x; - pointPositions[ pointOffset + 1 ] = _vector3.y; - pointPositions[ pointOffset + 2 ] = _vector3.z; - - pointDistances[ pointLength ] = distance; - - if( light.physicalFalloff ) { - // magic value of -1 switches the equation to UE4 physical quadratic falloff. - pointDecayExponents[ pointLength ] = -1.0; - } - else { - pointDecayExponents[ pointLength ] = ( distance === 0 ) ? 0.0 : light.decayExponent; - } - - pointLength += 1; - - } else if ( light instanceof THREE.SpotLight ) { - - spotCount += 1; - - if ( ! light.visible ) continue; - - spotOffset = spotLength * 3; - - setColorLinear( spotColors, spotOffset, color, intensity ); - - _vector3.setFromMatrixPosition( light.matrixWorld ); - - spotPositions[ spotOffset ] = _vector3.x; - spotPositions[ spotOffset + 1 ] = _vector3.y; - spotPositions[ spotOffset + 2 ] = _vector3.z; - - spotDistances[ spotLength ] = distance; - - if( light.physicalFalloff ) { - // magic value of -1 switches the equation to UE4 physical quadratic falloff. - spotDecayExponents[ pointLength ] = -1.0; - } - else { - spotDecayExponents[ pointLength ] = ( distance === 0 ) ? 0.0 : light.decayExponent; - } - - _direction.copy( _vector3 ); - _vector3.setFromMatrixPosition( light.target.matrixWorld ); - _direction.sub( _vector3 ); - _direction.normalize(); - - spotDirections[ spotOffset ] = _direction.x; - spotDirections[ spotOffset + 1 ] = _direction.y; - spotDirections[ spotOffset + 2 ] = _direction.z; - - spotAnglesCos[ spotLength ] = Math.cos( light.angle ); - spotExponents[ spotLength ] = light.exponent; - - spotLength += 1; - - } else if ( light instanceof THREE.HemisphereLight ) { - - hemiCount += 1; - - if ( ! light.visible ) continue; - - _direction.setFromMatrixPosition( light.matrixWorld ); - _direction.normalize(); - - // skip lights with undefined direction - // these create troubles in OpenGL (making pixel black) - - if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; - - hemiOffset = hemiLength * 3; - - hemiPositions[ hemiOffset ] = _direction.x; - hemiPositions[ hemiOffset + 1 ] = _direction.y; - hemiPositions[ hemiOffset + 2 ] = _direction.z; - - skyColor = light.color; - groundColor = light.groundColor; - - setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); - setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); - - hemiLength += 1; - - } else if ( light instanceof THREE.AreaLight ) { - - areaCount += 1; - - if ( ! light.visible ) continue; - - areaOffset = areaLength * 3; - - setColorLinear( areaColors, areaOffset, color, intensity ); - - _vector3.setFromMatrixPosition( light.matrixWorld ); - - areaPositions[ areaOffset ] = _vector3.x; - areaPositions[ areaOffset + 1 ] = _vector3.y; - areaPositions[ areaOffset + 2 ] = _vector3.z; - - areaDistances[ areaLength ] = distance; - areaDecayExponents[ areaLength ] = light.decayExponent; - - light.matrixWorld.extractBasis( _width, _height, _vector3 ); - _width.multiplyScalar( light.width ); - _height.multiplyScalar( light.height ); - - areaWidths[ areaOffset ] = _width.x; - areaWidths[ areaOffset + 1 ] = _width.y; - areaWidths[ areaOffset + 2 ] = _width.z; - - areaHeights[ areaOffset ] = _height.x; - areaHeights[ areaOffset + 1 ] = _height.y; - areaHeights[ areaOffset + 2 ] = _height.z; - - areaLength += 1; - - } - - } - - // null eventual remains from removed lights - // (this is to avoid if in shader) - - for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0; - for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0; - for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0; - for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0; - for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0; - for ( l = areaLength * 3, ll = Math.max( areaColors.length, areaCount * 3 ); l < ll; l ++ ) areaColors[ l ] = 0.0; - - zlights.directional.length = dirLength; - zlights.point.length = pointLength; - zlights.spot.length = spotLength; - zlights.hemi.length = hemiLength; - zlights.area.length = areaLength; - - zlights.ambient[ 0 ] = r; - zlights.ambient[ 1 ] = g; - zlights.ambient[ 2 ] = b; - - }; - - // GL state setting - - this.setFaceCulling = function ( cullFace, frontFaceDirection ) { - - if ( cullFace === THREE.CullFaceNone ) { - - _gl.disable( _gl.CULL_FACE ); - - } else { - - if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) { - - _gl.frontFace( _gl.CW ); - - } else { - - _gl.frontFace( _gl.CCW ); - - } - - if ( cullFace === THREE.CullFaceBack ) { - - _gl.cullFace( _gl.BACK ); - - } else if ( cullFace === THREE.CullFaceFront ) { - - _gl.cullFace( _gl.FRONT ); - - } else { - - _gl.cullFace( _gl.FRONT_AND_BACK ); - - } - - _gl.enable( _gl.CULL_FACE ); - - } - - }; - - this.setMaterialFaces = function ( material ) { - - var doubleSided = material.side === THREE.DoubleSide; - var flipSided = material.side === THREE.BackSide; - - if ( _oldDoubleSided !== doubleSided ) { - - if ( doubleSided ) { - - _gl.disable( _gl.CULL_FACE ); - - } else { - - _gl.enable( _gl.CULL_FACE ); - - } - - _oldDoubleSided = doubleSided; - - } - - if ( _oldFlipSided !== flipSided ) { - - if ( flipSided ) { - - _gl.frontFace( _gl.CW ); - - } else { - - _gl.frontFace( _gl.CCW ); - - } - - _oldFlipSided = flipSided; - - } - - }; - - this.setDepthTest = function ( depthTest ) { - - if ( _oldDepthTest !== depthTest ) { - - if ( depthTest ) { - - _gl.enable( _gl.DEPTH_TEST ); - - } else { - - _gl.disable( _gl.DEPTH_TEST ); - - } - - _oldDepthTest = depthTest; - - } - - }; - - this.setDepthWrite = function ( depthWrite ) { - - if ( _oldDepthWrite !== depthWrite ) { - - _gl.depthMask( depthWrite ); - _oldDepthWrite = depthWrite; - - } - - }; - - function setLineWidth ( width ) { - - if ( width !== _oldLineWidth ) { - - _gl.lineWidth( width ); - - _oldLineWidth = width; - - } - - }; - - function setPolygonOffset ( polygonoffset, factor, units ) { - - if ( _oldPolygonOffset !== polygonoffset ) { - - if ( polygonoffset ) { - - _gl.enable( _gl.POLYGON_OFFSET_FILL ); - - } else { - - _gl.disable( _gl.POLYGON_OFFSET_FILL ); - - } - - _oldPolygonOffset = polygonoffset; - - } - - if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) { - - _gl.polygonOffset( factor, units ); - - _oldPolygonOffsetFactor = factor; - _oldPolygonOffsetUnits = units; - - } - - }; - - this.setBlending = function ( blending, blendEquation, blendSrc, blendDst ) { - - if ( blending !== _oldBlending ) { - - if ( blending === THREE.NoBlending ) { - - _gl.disable( _gl.BLEND ); - - } else if ( blending === THREE.AdditiveBlending ) { - - _gl.enable( _gl.BLEND ); - _gl.blendEquation( _gl.FUNC_ADD ); - _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE ); - - } else if ( blending === THREE.SubtractiveBlending ) { - - // TODO: Find blendFuncSeparate() combination - _gl.enable( _gl.BLEND ); - _gl.blendEquation( _gl.FUNC_ADD ); - _gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR ); - - } else if ( blending === THREE.MultiplyBlending ) { - - // TODO: Find blendFuncSeparate() combination - _gl.enable( _gl.BLEND ); - _gl.blendEquation( _gl.FUNC_ADD ); - _gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR ); - - } else if ( blending === THREE.CustomBlending ) { - - _gl.enable( _gl.BLEND ); - - } else { - - _gl.enable( _gl.BLEND ); - _gl.blendEquationSeparate( _gl.FUNC_ADD, _gl.FUNC_ADD ); - _gl.blendFuncSeparate( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA ); - - } - - _oldBlending = blending; - - } - - if ( blending === THREE.CustomBlending ) { - - if ( blendEquation !== _oldBlendEquation ) { - - _gl.blendEquation( paramThreeToGL( blendEquation ) ); - - _oldBlendEquation = blendEquation; - - } - - if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst ) { - - _gl.blendFunc( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ) ); - - _oldBlendSrc = blendSrc; - _oldBlendDst = blendDst; - - } - - } else { - - _oldBlendEquation = null; - _oldBlendSrc = null; - _oldBlendDst = null; - - } - - }; - - // Defines - - function generateDefines ( defines ) { - - var value, chunk, chunks = []; - - for ( var d in defines ) { - - value = defines[ d ]; - if ( value === false ) continue; - - chunk = "#define " + d + " " + value; - chunks.push( chunk ); - - } - - return chunks.join( "\n" ); - - }; - - // Shaders - - function buildProgram( shaderID, fragmentShader, vertexShader, uniforms, attributes, defines, parameters, index0AttributeName ) { - - var p, pl, d, program, code; - var simpleChunks = []; - var chunks = []; - - // Generate code - - if ( shaderID ) { - - chunks.push( shaderID ); - simpleChunks.push( shaderID ); - - } else { - - chunks.push( fragmentShader ); - chunks.push( vertexShader ); - - } - - for ( d in defines ) { - - chunks.push( d ); - chunks.push( defines[ d ] ); - simpleChunks.push( d ); - simpleChunks.push( defines[ d ] ); - - } - - for ( p in parameters ) { - - chunks.push( p ); - chunks.push( parameters[ p ] ); - - simpleChunks.push( p ); - simpleChunks.push( parameters[ p ] ); - - } - - code = chunks.join(); - var simpleCode = simpleChunks.join(); - - // Check if code has been already compiled - - for ( p = 0, pl = _programs.length; p < pl; p ++ ) { - - var programInfo = _programs[ p ]; - - if ( programInfo.code.length === code.length && programInfo.code === code ) { - - programInfo.usedTimes ++; - - return programInfo.program; - - } - - } - - var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC"; - - if ( parameters.shadowMapType === THREE.PCFShadowMap ) { - - shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF"; - - } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) { - - shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT"; - - } - - var customDefines = generateDefines( defines ); - - program = _gl.createProgram(); - - var supportsShaderTextureLOD = ( _glExtensionShaderTextureLOD !== null ); - - var prefix_vertex = [ - - "precision " + _precision + " float;", - "precision " + _precision + " int;", - - customDefines, - - _supportsVertexTextures ? "#define VERTEX_TEXTURES" : "", - - _this.gammaInput ? "#define GAMMA_INPUT" : "", - _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", - - "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, - "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, - "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, - "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, - "#define MAX_AREA_LIGHTS " + parameters.maxAreaLights, - - "#define MAX_SHADOWS " + parameters.maxShadows, - - "#define MAX_BONES " + parameters.maxBones, - - parameters.map ? "#define USE_MAP" : "", - parameters.opacityMap ? "#define USE_OPACITYMAP" : "", - parameters.falloffMap ? "#define USE_FALLOFFMAP" : "", - parameters.translucencyMap ? "#define USE_TRANSLUCENCYMAP" : "", - parameters.envMap ? "#define USE_ENVMAP" : "", - parameters.diffuseEnvMap ? "#define USE_DIFFUSEENVMAP" : "", - parameters.lightMap ? "#define USE_LIGHTMAP" : "", - parameters.emissiveMap ? "#define USE_EMISSIVEMAP" : "", - parameters.bumpMap ? "#define USE_BUMPMAP" : "", - parameters.reflectivityMap ? "#define USE_REFLECTIVITYMAP" : "", - parameters.roughnessMap ? "#define USE_ROUGHNESSMAP" : "", - parameters.metallicMap ? "#define USE_METALLICMAP" : "", - parameters.normalMap ? "#define USE_NORMALMAP" : "", - parameters.specularMap ? "#define USE_SPECULARMAP" : "", - parameters.vertexColors ? "#define USE_COLOR" : "", - parameters.clearCoat ? "#define CLEARCOAT" : "", - - parameters.anisotropy ? "#define ANISOTROPY" : "", - parameters.anisotropyMap ? "#define USE_ANISOTROPYMAP" : "", - ( parameters.anisotropy && parameters.anisotropyRotation ) ? "#define ANISOTROPYROTATION" : "", - ( parameters.anisotropy && parameters.anisotropyRotationMap ) ? "#define USE_ANISOTROPYROTATIONMAP" : "", - - parameters.skinning ? "#define USE_SKINNING" : "", - parameters.useVertexTexture ? "#define BONE_TEXTURE" : "", - - parameters.morphTargets ? "#define USE_MORPHTARGETS" : "", - parameters.morphNormals ? "#define USE_MORPHNORMALS" : "", - parameters.wrapAround ? "#define WRAP_AROUND" : "", - parameters.doubleSided ? "#define DOUBLE_SIDED" : "", - parameters.flipSided ? "#define FLIP_SIDED" : "", - - parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", - parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", - parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", - parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", - - parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "", - - "uniform mat4 modelMatrix;", - "uniform mat4 modelViewMatrix;", - "uniform mat4 projectionMatrix;", - "uniform mat4 viewMatrix;", - "uniform mat3 normalMatrix;", - "uniform vec3 cameraPosition;", - - "attribute vec3 position;", - "attribute vec3 normal;", - "attribute vec2 uv;", - "attribute vec2 uv2;", - - "#ifdef USE_COLOR", - - "attribute vec3 color;", - - "#endif", - - "#ifdef USE_MORPHTARGETS", - - "attribute vec3 morphTarget0;", - "attribute vec3 morphTarget1;", - "attribute vec3 morphTarget2;", - "attribute vec3 morphTarget3;", - - "#ifdef USE_MORPHNORMALS", - - "attribute vec3 morphNormal0;", - "attribute vec3 morphNormal1;", - "attribute vec3 morphNormal2;", - "attribute vec3 morphNormal3;", - - "#else", - - "attribute vec3 morphTarget4;", - "attribute vec3 morphTarget5;", - "attribute vec3 morphTarget6;", - "attribute vec3 morphTarget7;", - - "#endif", - - "#endif", - - "#ifdef USE_SKINNING", - - "attribute vec4 skinIndex;", - "attribute vec4 skinWeight;", - - "#endif", - - "" - - ].join("\n"); - - - var prefix_fragment = [ - - "precision " + _precision + " float;", - "precision " + _precision + " int;", - - ( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "", - - customDefines, - - "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, - "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, - "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, - "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, - "#define MAX_AREA_LIGHTS " + parameters.maxAreaLights, - - "#define MAX_SHADOWS " + parameters.maxShadows, - - parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "", - - _this.gammaInput ? "#define GAMMA_INPUT" : "", - _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", - - ( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "", - ( parameters.useFog && parameters.fogExp ) ? "#define FOG_EXP2" : "", - - parameters.map ? "#define USE_MAP" : "", - parameters.opacityMap ? "#define USE_OPACITYMAP" : "", - parameters.falloffMap ? "#define USE_FALLOFFMAP" : "", - parameters.translucencyMap ? "#define USE_TRANSLUCENCYMAP" : "", - parameters.envMap ? "#define USE_ENVMAP" : "", - parameters.diffuseEnvMap ? "#define USE_DIFFUSEENVMAP" : "", - parameters.lightMap ? "#define USE_LIGHTMAP" : "", - parameters.emissiveMap ? "#define USE_EMISSIVEMAP" : "", - parameters.bumpMap ? "#define USE_BUMPMAP" : "", - parameters.reflectivityMap ? "#define USE_REFLECTIVITYMAP" : "", - parameters.roughnessMap ? "#define USE_ROUGHNESSMAP" : "", - parameters.metallicMap ? "#define USE_METALLICMAP" : "", - parameters.normalMap ? "#define USE_NORMALMAP" : "", - parameters.specularMap ? "#define USE_SPECULARMAP" : "", - parameters.vertexColors ? "#define USE_COLOR" : "", - parameters.clearCoat ? "#define CLEARCOAT" : "", - - parameters.translucency ? "#define TRANSLUCENCY" : "", - - parameters.anisotropy ? "#define ANISOTROPY" : "", - parameters.anisotropyMap ? "#define USE_ANISOTROPYMAP" : "", - ( parameters.anisotropy && parameters.anisotropyRotation ) ? "#define ANISOTROPYROTATION" : "", - ( parameters.anisotropy && parameters.anisotropyRotationMap ) ? "#define USE_ANISOTROPYROTATIONMAP" : "", - - parameters.falloff ? "#define FALLOFF" : "", - - parameters.wrapAround ? "#define WRAP_AROUND" : "", - parameters.doubleSided ? "#define DOUBLE_SIDED" : "", - parameters.flipSided ? "#define FLIP_SIDED" : "", - - parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", - parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", - parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", - parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", - - supportsShaderTextureLOD ? "#define TEXTURE_CUBE_LOD_EXT" : "", - - "uniform mat4 viewMatrix;", - "uniform vec3 cameraPosition;", - "" - - ].join("\n"); - - var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader, shaderID, simpleCode ); - var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader, shaderID, simpleCode ); - - _gl.attachShader( program, glVertexShader, code ); - _gl.attachShader( program, glFragmentShader, code ); - - // Force a particular attribute to index 0. - // because potentially expensive emulation is done by browser if attribute 0 is disabled. - // And, color, for example is often automatically bound to index 0 so disabling it - if ( index0AttributeName !== undefined ) { - - _gl.bindAttribLocation( program, 0, index0AttributeName ); - - } - - _gl.linkProgram( program ); - - var programLogInfo = _gl.getProgramInfoLog( program ); - - if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) { - - var gl_error_message = _gl.getError(); - THREE.onerror( shaderID + ' shader program error: ' + gl_error_message + '\n ' + programLogInfo, { - shaderID: shaderID, - programInfo: programLogInfo, - glError: gl_error_message, - vertexShader: prefix_vertex + vertexShader, - fragmentShader: prefix_fragment + fragmentShader, - getProgramParameter_LINK_STATUS: _gl.getProgramParameter( program, _gl.LINK_STATUS ), - getProgramParameter_VALIDATE_STATUS: _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ), - getProgramParameter_ATTACHED_SHADERS: _gl.getProgramParameter( program, _gl.ATTACHED_SHADERS ), - getProgramParameter_ACTIVE_ATTRIBUTES: _gl.getProgramParameter( program, _gl.ACTIVE_ATTRIBUTES ), - getProgramParameter_ACTIVE_UNIFORMS: _gl.getProgramParameter( program, _gl.ACTIVE_UNIFORMS ), - gl_MAX_VARYING_VECTORS: _gl.getParameter(_gl.MAX_VARYING_VECTORS), - gl_MAX_VERTEX_ATTRIBS: _gl.getParameter(_gl.MAX_VERTEX_ATTRIBS), - gl_MAX_VERTEX_UNIFORM_VECTORS: _gl.getParameter(_gl.MAX_VERTEX_UNIFORM_VECTORS), - gl_MAX_VERTEX_TEXTURE_IMAGE_UNITS: _gl.getParameter(_gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS), - gl_MAX_FRAGMENT_UNIFORM_VECTORS: _gl.getParameter(_gl.MAX_FRAGMENT_UNIFORM_VECTORS), - gl_MAX_TEXTURE_IMAGE_UNITS: _gl.getParameter(_gl.MAX_TEXTURE_IMAGE_UNITS) - } ); - } - - // clean up - - _gl.deleteShader( glFragmentShader ); - _gl.deleteShader( glVertexShader ); - - program.uniforms = {}; - program.attributes = {}; - - var identifiers, u, a, i; - - // cache uniform locations - - identifiers = [ - - 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition', - 'morphTargetInfluences' - - ]; - - if ( parameters.useVertexTexture ) { - - identifiers.push( 'boneTexture' ); - identifiers.push( 'boneTextureWidth' ); - identifiers.push( 'boneTextureHeight' ); - - } else { - - identifiers.push( 'boneGlobalMatrices' ); - - } - - for ( u in uniforms ) { - - identifiers.push( u ); - - } - - cacheUniformLocations( program, identifiers ); - - // cache attributes locations - - identifiers = [ - - "position", "normal", "uv", "uv2", "tangent", "color", - "skinIndex", "skinWeight", "lineDistance" - - ]; - - for ( i = 0; i < parameters.maxMorphTargets; i ++ ) { - - identifiers.push( "morphTarget" + i ); - - } - - for ( i = 0; i < parameters.maxMorphNormals; i ++ ) { - - identifiers.push( "morphNormal" + i ); - - } - - for ( a in attributes ) { - - identifiers.push( a ); - - } - - cacheAttributeLocations( program, identifiers ); - - program.id = _programs_counter ++; - - _programs.push( { program: program, code: code, usedTimes: 1 } ); - - _this.info.memory.programs = _programs.length; - - return program; - - }; - - // Shader parameters cache - - function cacheUniformLocations ( program, identifiers ) { - - var i, l, id; - - for( i = 0, l = identifiers.length; i < l; i ++ ) { - - id = identifiers[ i ]; - program.uniforms[ id ] = _gl.getUniformLocation( program, id ); - - } - - }; - - function cacheAttributeLocations ( program, identifiers ) { - - var i, l, id; - - for( i = 0, l = identifiers.length; i < l; i ++ ) { - - id = identifiers[ i ]; - program.attributes[ id ] = _gl.getAttribLocation( program, id ); - - } - - }; - - function addLineNumbers ( string ) { - - var chunks = string.split( "\n" ); - - for ( var i = 0, il = chunks.length; i < il; i ++ ) { - - // Chrome reports shader errors on lines - // starting counting from 1 - - chunks[ i ] = ( i + 1 ) + ": " + chunks[ i ]; - - } - - return chunks.join( "\n" ); - - }; - - function getShader ( type, string, shaderID, simpleCode ) { - - var shader; - - if ( type === "fragment" ) { - - shader = _gl.createShader( _gl.FRAGMENT_SHADER ); - - } else if ( type === "vertex" ) { - - shader = _gl.createShader( _gl.VERTEX_SHADER ); - - } - - _gl.shaderSource( shader, string ); - _gl.compileShader( shader ); - - if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) { - - THREE.onerror( "shader error: " + shaderID + "." + type, { - getShaderParameter: _gl.getShaderParameter( shader, _gl.COMPILE_STATUS ), - shaderInfoLog: _gl.getShaderInfoLog( shader ), - shaderCode: addLineNumbers( string ), - getError: _gl.getError(), - simpleCode: simpleCode, - gl_MAX_VARYING_VECTORS: _gl.getParameter(_gl.MAX_VARYING_VECTORS), - gl_MAX_VERTEX_ATTRIBS: _gl.getParameter(_gl.MAX_VERTEX_ATTRIBS), - gl_MAX_VERTEX_UNIFORM_VECTORS: _gl.getParameter(_gl.MAX_VERTEX_UNIFORM_VECTORS), - gl_MAX_VERTEX_TEXTURE_IMAGE_UNITS: _gl.getParameter(_gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS), - gl_MAX_FRAGMENT_UNIFORM_VECTORS: _gl.getParameter(_gl.MAX_FRAGMENT_UNIFORM_VECTORS), - gl_MAX_TEXTURE_IMAGE_UNITS: _gl.getParameter(_gl.MAX_TEXTURE_IMAGE_UNITS) - } ); - - return null; - - } - - return shader; - - }; - - // Textures - - function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) { - - if ( isImagePowerOfTwo ) { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) ); - - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) ); - - } else { - - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - - _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); - _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); - - } - - if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) { - - if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) { - - _gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) ); - texture.__oldAnisotropy = texture.anisotropy; - - } - - } - - }; - - var _reportIfError = function ( description, optionalData ) { - var errorCode = _gl.getError(); - if( errorCode === _gl.NO_ERROR ) { - return; - } - var errorMessage = ""; - if( errorCode === _gl.OUT_OF_MEMORY ) { - errorMessage = "OUT_OF_MEMORY"; - } - else if( errorCode === _gl.INVALID_ENUM ) { - errorMessage = "INVALID_ENUM"; - } - else if( errorCode === _gl.INVALID_OPERATION ) { - errorMessage = "INVALID_OPERATION"; - } - else if( errorCode === _gl.INVALID_VALUE ) { - errorMessage = "INVALID_VALUE"; - } - else if( errorCode === _gl.INVALID_FRAMEBUFFER_OPERATION ) { - errorMessage = "INVALID_FRAMEBUFFER_OPERATION"; - } - else if( errorCode === _gl.CONTEXT_LOST_WEBGL ) { - errorMessage = "CONTEXT_LOST_WEBGL"; - } - else if( errorCode === _gl.NO_ERROR ) { - errorMessage = "NO_ERROR"; - } - else { - errorMessage = "Unknown code: " + errorCode; - } - THREE.onerror( "WebGL Error: " + errorMessage + " (" + description + ")", optionalData ); - }; - - this.setTexture = function ( texture, slot ) { - - if ( texture.needsUpdate ) { - - if ( ! texture.__webglInit ) { - - texture.__webglInit = true; - - texture.addEventListener( 'dispose', onTextureDispose ); - - texture.__webglTexture = _gl.createTexture(); - - _this.info.memory.textures ++; - - } - - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); - - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); - _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); - - var image = texture.image, - isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), - glFormat = paramThreeToGL( texture.format ), - glType = paramThreeToGL( texture.type ); - - setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo ); - - var mipmap, mipmaps = texture.mipmaps; - - if ( texture instanceof THREE.DataTexture ) { - - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels - - if ( mipmaps.length > 0 && isImagePowerOfTwo ) { - - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - _reportIfError( "_gl.texImage2D DataTexture Mipmaps, texture.name: " + texture.name, texture ); - } - - texture.generateMipmaps = false; - - } else { - - _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); - _reportIfError( "_gl.texImage2D DataTexture, texture.name: " + texture.name, texture ); - } - - } else if ( texture instanceof THREE.CompressedTexture ) { - - for( var i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - if ( texture.format!==THREE.RGBAFormat ) { - _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - _reportIfError( "_gl.texImage2D CompressedTexture Non RGBA, texture.name: " + texture.name, texture ); - } else { - _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - _reportIfError( "_gl.texImage2D CompressedTexture, texture.name: " + texture.name, texture ); - } - - } - - } else { // regular Texture (image, video, canvas) - - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels - - if ( mipmaps.length > 0 && isImagePowerOfTwo ) { - - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); - _reportIfError( "_gl.texImage2D Mipmaps, texture.name: " + texture.name, texture ); - - } - - texture.generateMipmaps = false; - - } else { - - _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image ); - _reportIfError( "_gl.texImage2D, texture.name: " + texture.name, texture ); - - } - - } - - if ( texture.generateMipmaps && isImagePowerOfTwo ) { - _gl.generateMipmap( _gl.TEXTURE_2D ); - _reportIfError( "_gl.generateMipmap, texture.name: " + texture.name, texture ); - } - - - texture.needsUpdate = false; - - if ( texture.onUpdate ) texture.onUpdate(); - - } else { - - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); - - } - - }; - - function clampToMaxSize ( image, maxSize ) { - - if ( image.width <= maxSize && image.height <= maxSize ) { - - return image; - - } - - // Warning: Scaling through the canvas will only work with images that use - // premultiplied alpha. - - var maxDimension = Math.max( image.width, image.height ); - var newWidth = Math.floor( image.width * maxSize / maxDimension ); - var newHeight = Math.floor( image.height * maxSize / maxDimension ); - - var canvas = document.createElement( 'canvas' ); - canvas.width = newWidth; - canvas.height = newHeight; - - var ctx = canvas.getContext( "2d" ); - ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight ); - - return canvas; - - } - - function setCubeTexture ( texture, slot ) { - - if ( texture.image.length === 6 ) { - - if ( texture.needsUpdate ) { - - if ( ! texture.image.__webglTextureCube ) { - - texture.addEventListener( 'dispose', onTextureDispose ); - - texture.image.__webglTextureCube = _gl.createTexture(); - - _this.info.memory.textures ++; - - } - - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); - - _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); - - var isCompressed = texture instanceof THREE.CompressedTexture; - - var cubeImage = []; - - for ( var i = 0; i < 6; i ++ ) { - - if ( _this.autoScaleCubemaps && ! isCompressed ) { - - cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize ); - - } else { - - cubeImage[ i ] = texture.image[ i ]; - - } - - } - - var image = cubeImage[ 0 ], - isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), - glFormat = paramThreeToGL( texture.format ), - glType = paramThreeToGL( texture.type ); - - setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo ); - - for ( var i = 0; i < 6; i ++ ) { - - if( !isCompressed ) { - - _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); - _reportIfError( "_gl.texImage2D CubeMap, texture.name: " + texture.name, { texture: texture, cubeImage: cubeImage, index: i } ); - - } else { - - var mipmap, mipmaps = cubeImage[ i ].mipmaps; - - for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { - - mipmap = mipmaps[ j ]; - if ( texture.format!==THREE.RGBAFormat ) { - - _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - _reportIfError( "_gl.compressedTexImage2D CubeMap Mipmaps Compressed, texture.name: " + texture.name, texture ); - - } else { - _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - _reportIfError( "_gl.texImage2D CubeMap Mipmaps Compressed RGBA, texture.name: " + texture.name, texture ); - } - - } - } - } - - if ( texture.generateMipmaps && isImagePowerOfTwo ) { - - _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - _reportIfError( "_gl.generateMipmap CubeMap Mipmaps, texture.name: " + texture.name, texture ); - - } - - texture.needsUpdate = false; - - if ( texture.onUpdate ) texture.onUpdate(); - - } else { - - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); - - } - - } - - }; - - function setCubeTextureDynamic ( texture, slot ) { - - _gl.activeTexture( _gl.TEXTURE0 + slot ); - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture ); - - }; - - // Render targets - - function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) { - - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 ); - - }; - - function setupRenderBuffer ( renderbuffer, renderTarget ) { - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); - - var optionsString = ""; - - if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - - optionsString = "renderTarget: " + renderTarget.width + "+" + renderTarget.height + " DEPTH_ATTACHMENT"; - - /* For some reason this is not working. Defaulting to RGBA4. - } else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - */ - } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); - - optionsString = "renderTarget: " + renderTarget.width + "+" + renderTarget.height + " DEPTH_STENCIL_ATTACHMENT"; - - } else { - - _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); - - optionsString = "renderTarget: " + renderTarget.width + "+" + renderTarget.height + " RGBA4"; - - } - - if (_gl.checkFramebufferStatus(_gl.FRAMEBUFFER) != _gl.FRAMEBUFFER_COMPLETE) { - console.log( renderTarget ); - throw new Error('(A) Rendering to this texture (renderTarget.name: ' + renderTarget.name + ') is not supported (incomplete framebuffer) ' + optionsString ); - } - - }; - - this.setRenderTarget = function ( renderTarget ) { - - var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); - - if ( renderTarget && ! renderTarget.__webglFramebuffer ) { - - if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true; - if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true; - - renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); - - renderTarget.__webglTexture = _gl.createTexture(); - - _this.info.memory.textures ++; - - // Setup texture, create render and frame buffers - - var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ), - glFormat = paramThreeToGL( renderTarget.format ), - glType = paramThreeToGL( renderTarget.type ); - - if ( isCube ) { - - renderTarget.__webglFramebuffer = []; - renderTarget.__webglRenderbuffer = []; - - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); - setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo ); - - for ( var i = 0; i < 6; i ++ ) { - - renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer(); - renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer(); - - _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); - _reportIfError( "_gl.texImage2D CubeMap, renderTarget.name: " + renderTarget.name, renderTarget ); - - setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); - setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget ); - - } - - if ( isTargetPowerOfTwo ) { - _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - _reportIfError( "_gl.generateMipmap, CubeMap, renderTarget.name: " + renderTarget.name, renderTarget ); - } - - } else { - - renderTarget.__webglFramebuffer = _gl.createFramebuffer(); - - if ( renderTarget.shareDepthFrom ) { - - renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer; - - } else { - - renderTarget.__webglRenderbuffer = _gl.createRenderbuffer(); - - } - - _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); - setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo ); - - _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); - _reportIfError( "_gl.texImage2D, renderTarget.name: " + renderTarget.name, renderTarget ); - - setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D ); - - if ( renderTarget.shareDepthFrom ) { - - var optionsString = "glFormat: " + glFormat + " glType: " + glType; - - if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); - - optionsString = " renderTarget: " + renderTarget.width + "+" + renderTarget.height + " DEPTH_ATTACHMENT"; - - } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - - _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); - - optionsString = " renderTarget: " + renderTarget.width + "+" + renderTarget.height + " DEPTH_STENCIL_ATTACHMENT"; - - } - - if (_gl.checkFramebufferStatus(_gl.FRAMEBUFFER) != _gl.FRAMEBUFFER_COMPLETE) { - throw new Error('(B) Rendering to this texture (renderTarget.name: ' + renderTarget.name + ') is not supported (incomplete framebuffer) ' + optionsString ); - } - - } else { - - setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget ); - - } - - if ( isTargetPowerOfTwo ) { - _gl.generateMipmap( _gl.TEXTURE_2D ); - _reportIfError( "_gl.generateMipmap, renderTarget.name: " + renderTarget.name, renderTarget ); - } - - - } - - // Release everything - - if ( isCube ) { - - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); - - } else { - - _gl.bindTexture( _gl.TEXTURE_2D, null ); - - } - - _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); - _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); - - } - - var framebuffer, width, height, vx, vy; - - if ( renderTarget ) { - - if ( isCube ) { - - framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ]; - - } else { - - framebuffer = renderTarget.__webglFramebuffer; - - } - - width = renderTarget.width; - height = renderTarget.height; - - vx = 0; - vy = 0; - - } else { - - framebuffer = null; - - width = _viewportWidth; - height = _viewportHeight; - - vx = _viewportX; - vy = _viewportY; - - } - - if ( framebuffer !== _currentFramebuffer ) { - - _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _gl.viewport( vx, vy, width, height ); - - _currentFramebuffer = framebuffer; - - } - - _currentWidth = width; - _currentHeight = height; - - }; - - function updateRenderTargetMipmap ( renderTarget ) { - - if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { - - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); - _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); - _reportIfError( "_gl.generateMipmap CubeMap, renderTarget.name: " + renderTarget.name, renderTarget ); - _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); - - } else { - - _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); - _gl.generateMipmap( _gl.TEXTURE_2D ); - _reportIfError( "_gl.generateMipmap, renderTarget.name: " + renderTarget.name, renderTarget ); - _gl.bindTexture( _gl.TEXTURE_2D, null ); - - } - - }; - - // Fallback filters for non-power-of-2 textures - - function filterFallback ( f ) { - - if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) { - - return _gl.NEAREST; - - } - - return _gl.LINEAR; - - }; - - // Map three.js constants to WebGL constants - - function paramThreeToGL ( p ) { - - if ( p === THREE.RepeatWrapping ) return _gl.REPEAT; - if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; - if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; - - if ( p === THREE.NearestFilter ) return _gl.NEAREST; - if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST; - if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR; - - if ( p === THREE.LinearFilter ) return _gl.LINEAR; - if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST; - if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR; - - if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE; - if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4; - if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1; - if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5; - - if ( p === THREE.ByteType ) return _gl.BYTE; - if ( p === THREE.ShortType ) return _gl.SHORT; - if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT; - if ( p === THREE.IntType ) return _gl.INT; - if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; - if ( p === THREE.FloatType ) return _gl.FLOAT; - if ( p === THREE.HalfType ) return 0x8D61; - - if ( p === THREE.AlphaFormat ) return _gl.ALPHA; - if ( p === THREE.RGBFormat ) return _gl.RGB; - if ( p === THREE.RGBAFormat ) return _gl.RGBA; - if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE; - if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA; - - if ( p === THREE.AddEquation ) return _gl.FUNC_ADD; - if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT; - if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT; - - if ( p === THREE.ZeroFactor ) return _gl.ZERO; - if ( p === THREE.OneFactor ) return _gl.ONE; - if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR; - if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR; - if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA; - if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA; - if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA; - if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA; - - if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR; - if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; - if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; - - if ( _glExtensionCompressedTextureS3TC !== undefined ) { - - if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT; - if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT; - if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT; - if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT; - - } - - return 0; - - }; - - // Allocations - - function allocateBones ( object ) { - - if ( _supportsBoneTextures && object && object.useVertexTexture ) { - - return 1024; - - } else { - - // default for when object is not specified - // ( for example when prebuilding shader - // to be used with multiple objects ) - // - // - leave some extra space for other uniforms - // - limit here is ANGLE's 254 max uniform vectors - // (up to 54 should be safe) - - var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS ); - var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); - - var maxBones = nVertexMatrices; - - if ( object !== undefined && object instanceof THREE.SkinnedMesh ) { - - maxBones = Math.min( object.bones.length, maxBones ); - - if ( maxBones < object.bones.length ) { - - THREE.onwarning( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" ); - - } - - } - - return maxBones; - - } - - }; - - function allocateLights( lights ) { - - var dirLights = 0; - var pointLights = 0; - var spotLights = 0; - var hemiLights = 0; - var areaLights = 0; - - for ( var l = 0, ll = lights.length; l < ll; l ++ ) { - - var light = lights[ l ]; - - if ( light.onlyShadow || light.visible === false ) continue; - - if ( light instanceof THREE.DirectionalLight ) dirLights ++; - if ( light instanceof THREE.PointLight ) pointLights ++; - if ( light instanceof THREE.SpotLight ) spotLights ++; - if ( light instanceof THREE.HemisphereLight ) hemiLights ++; - if ( light instanceof THREE.AreaLight ) areaLights ++; - - } - - return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights, 'area': areaLights }; - - }; - - function allocateShadows( lights ) { - - var maxShadows = 0; - - for ( var l = 0, ll = lights.length; l < ll; l++ ) { - - var light = lights[ l ]; - - if ( ! light.castShadow ) continue; - - if ( light instanceof THREE.SpotLight ) maxShadows ++; - if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++; - - } - - return maxShadows; - - }; - - // Initialization - - function initGL() { - - try { - - var attributes = { - alpha: _alpha, - premultipliedAlpha: _premultipliedAlpha, - antialias: _antialias, - stencil: _stencil, - preserveDrawingBuffer: _preserveDrawingBuffer - }; - - _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes ); - - if ( _gl === null ) { - - THREE.onerror( 'Error creating WebGL context.' ); - - } - - } catch ( error ) { - - THREE.onerror( error ); - - } - - _glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' ); - _glExtensionTextureFloatLinear = _gl.getExtension( 'OES_texture_float_linear' ); - _glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' ); - _glExtensionShaderTextureLOD = _gl.getExtension( 'EXT_shader_texture_lod' ); - - _glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); - - _glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); - - if ( ! _glExtensionTextureFloat ) { - - console.log( 'THREE.WebGLRenderer: Float textures not supported.' ); - - } - - if ( ! _glExtensionStandardDerivatives ) { - - console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' ); - - } - - if ( ! _glExtensionShaderTextureLOD ) { - - console.log( 'THREE.WebGLRenderer: Shader texture LOD not supported.' ); - - } - - if ( ! _glExtensionTextureFilterAnisotropic ) { - - console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' ); - - } - - if ( ! _glExtensionCompressedTextureS3TC ) { - - console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' ); - - } - - if ( _gl.getShaderPrecisionFormat === undefined ) { - - _gl.getShaderPrecisionFormat = function() { - - return { - "rangeMin" : 1, - "rangeMax" : 1, - "precision" : 1 - }; - - } - } - - }; - - function setDefaultGLState () { - - _gl.clearColor( 0, 0, 0, 1 ); - _gl.clearDepth( 1 ); - _gl.clearStencil( 0 ); - - _gl.enable( _gl.DEPTH_TEST ); - _gl.depthFunc( _gl.LEQUAL ); - - _gl.frontFace( _gl.CCW ); - _gl.cullFace( _gl.BACK ); - _gl.enable( _gl.CULL_FACE ); - - _gl.enable( _gl.BLEND ); - _gl.blendEquation( _gl.FUNC_ADD ); - _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA ); - - _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); - - _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); - - }; - - // default plugins (order is important) - - this.shadowMapPlugin = new THREE.ShadowMapPlugin(); - this.addPrePlugin( this.shadowMapPlugin ); - - this.addPostPlugin( new THREE.SpritePlugin() ); - this.addPostPlugin( new THREE.LensFlarePlugin() ); - -}; - -/** - * @author szimek / https://github.com/szimek/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.WebGLRenderTarget = function ( width, height, options, name ) { - - this.name = name || ""; - this.width = width; - this.height = height; - - options = options || {}; - - this.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping; - this.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping; - - this.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter; - this.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter; - - this.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1; - - this.offset = new THREE.Vector2( 0, 0 ); - this.repeat = new THREE.Vector2( 1, 1 ); - - this.format = options.format !== undefined ? options.format : THREE.RGBAFormat; - this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType; - - this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; - this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; - - this.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; - - this.shareDepthFrom = null; - -}; - -THREE.WebGLRenderTarget.prototype = { - - constructor: THREE.WebGLRenderTarget, - - clone: function () { - - var tmp = new THREE.WebGLRenderTarget( this.width, this.height, null, this.name + " Clone" ); - - tmp.wrapS = this.wrapS; - tmp.wrapT = this.wrapT; - - tmp.magFilter = this.magFilter; - tmp.minFilter = this.minFilter; - - tmp.anisotropy = this.anisotropy; - - tmp.offset.copy( this.offset ); - tmp.repeat.copy( this.repeat ); - - tmp.format = this.format; - tmp.type = this.type; - - tmp.depthBuffer = this.depthBuffer; - tmp.stencilBuffer = this.stencilBuffer; - - tmp.generateMipmaps = this.generateMipmaps; - - tmp.shareDepthFrom = this.shareDepthFrom; - - return tmp; - - }, - - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); - - } - -}; - -THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype ); - -/** - * @author alteredq / http://alteredqualia.com - */ - -THREE.WebGLRenderTargetCube = function ( width, height, options ) { - - THREE.WebGLRenderTarget.call( this, width, height, options ); - - this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 - -}; - -THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.RenderableVertex = function () { - - this.position = new THREE.Vector3(); - this.positionWorld = new THREE.Vector3(); - this.positionScreen = new THREE.Vector4(); - - this.visible = true; - -}; - -THREE.RenderableVertex.prototype.copy = function ( vertex ) { - - this.positionWorld.copy( vertex.positionWorld ); - this.positionScreen.copy( vertex.positionScreen ); - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.RenderableFace = function () { - - this.id = 0; - - this.v1 = new THREE.RenderableVertex(); - this.v2 = new THREE.RenderableVertex(); - this.v3 = new THREE.RenderableVertex(); - - this.centroidModel = new THREE.Vector3(); - - this.normalModel = new THREE.Vector3(); - - this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; - this.vertexNormalsLength = 0; - - this.color = null; - this.material = null; - this.uvs = [[]]; - - this.z = 0; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.RenderableObject = function () { - - this.id = 0; - - this.object = null; - this.z = 0; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.RenderableSprite = function () { - - this.id = 0; - - this.object = null; - - this.x = 0; - this.y = 0; - this.z = 0; - - this.rotation = 0; - this.scale = new THREE.Vector2(); - - this.material = null; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.RenderableLine = function () { - - this.id = 0; - - this.v1 = new THREE.RenderableVertex(); - this.v2 = new THREE.RenderableVertex(); - - this.vertexColors = [ new THREE.Color(), new THREE.Color() ]; - this.material = null; - - this.z = 0; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.GeometryUtils = { - - // Merge two geometries or geometry and geometry from object (using object's transform) - - merge: function ( geometry1, object2 /* mesh | geometry */, materialIndexOffset ) { - - var matrix, normalMatrix, - vertexOffset = geometry1.vertices.length, - uvPosition = geometry1.faceVertexUvs[ 0 ].length, - geometry2 = object2 instanceof THREE.Mesh ? object2.geometry : object2, - vertices1 = geometry1.vertices, - vertices2 = geometry2.vertices, - faces1 = geometry1.faces, - faces2 = geometry2.faces, - uvs1 = geometry1.faceVertexUvs[ 0 ], - uvs2 = geometry2.faceVertexUvs[ 0 ]; - - if ( materialIndexOffset === undefined ) materialIndexOffset = 0; - - if ( object2 instanceof THREE.Mesh ) { - - object2.matrixAutoUpdate && object2.updateMatrix(); - - matrix = object2.matrix; - - normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); - - } - - // vertices - - for ( var i = 0, il = vertices2.length; i < il; i ++ ) { - - var vertex = vertices2[ i ]; - - var vertexCopy = vertex.clone(); - - if ( matrix ) vertexCopy.applyMatrix4( matrix ); - - vertices1.push( vertexCopy ); - - } - - // faces - - for ( i = 0, il = faces2.length; i < il; i ++ ) { - - var face = faces2[ i ], faceCopy, normal, color, - faceVertexNormals = face.vertexNormals, - faceVertexColors = face.vertexColors; - - faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); - faceCopy.normal.copy( face.normal ); - - if ( normalMatrix ) { - - faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); - - } - - for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { - - normal = faceVertexNormals[ j ].clone(); - - if ( normalMatrix ) { - - normal.applyMatrix3( normalMatrix ).normalize(); - - } - - faceCopy.vertexNormals.push( normal ); - - } - - faceCopy.color.copy( face.color ); - - for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { - - color = faceVertexColors[ j ]; - faceCopy.vertexColors.push( color.clone() ); - - } - - faceCopy.materialIndex = face.materialIndex + materialIndexOffset; - - faceCopy.centroid.copy( face.centroid ); - - if ( matrix ) { - - faceCopy.centroid.applyMatrix4( matrix ); - - } - - faces1.push( faceCopy ); - - } - - // uvs - - for ( i = 0, il = uvs2.length; i < il; i ++ ) { - - var uv = uvs2[ i ], uvCopy = []; - - for ( var j = 0, jl = uv.length; j < jl; j ++ ) { - - uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); - - } - - uvs1.push( uvCopy ); - - } - - }, - - // Get random point in triangle (via barycentric coordinates) - // (uniform distribution) - // http://www.cgafaq.info/wiki/Random_Point_In_Triangle - - randomPointInTriangle: function () { - - var vector = new THREE.Vector3(); - - return function ( vectorA, vectorB, vectorC ) { - - var point = new THREE.Vector3(); - - var a = THREE.Math.random16(); - var b = THREE.Math.random16(); - - if ( ( a + b ) > 1 ) { - - a = 1 - a; - b = 1 - b; - - } - - var c = 1 - a - b; - - point.copy( vectorA ); - point.multiplyScalar( a ); - - vector.copy( vectorB ); - vector.multiplyScalar( b ); - - point.add( vector ); - - vector.copy( vectorC ); - vector.multiplyScalar( c ); - - point.add( vector ); - - return point; - - }; - - }(), - - // Get random point in face (triangle / quad) - // (uniform distribution) - - randomPointInFace: function ( face, geometry, useCachedAreas ) { - - var vA, vB, vC, vD; - - vA = geometry.vertices[ face.a ]; - vB = geometry.vertices[ face.b ]; - vC = geometry.vertices[ face.c ]; - - return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC ); - - }, - - // Get uniformly distributed random points in mesh - // - create array with cumulative sums of face areas - // - pick random number from 0 to total area - // - find corresponding place in area array by binary search - // - get random point in face - - randomPointsInGeometry: function ( geometry, n ) { - - var face, i, - faces = geometry.faces, - vertices = geometry.vertices, - il = faces.length, - totalArea = 0, - cumulativeAreas = [], - vA, vB, vC, vD; - - // precompute face areas - - for ( i = 0; i < il; i ++ ) { - - face = faces[ i ]; - - vA = vertices[ face.a ]; - vB = vertices[ face.b ]; - vC = vertices[ face.c ]; - - face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC ); - - totalArea += face._area; - - cumulativeAreas[ i ] = totalArea; - - } - - // binary search cumulative areas array - - function binarySearchIndices( value ) { - - function binarySearch( start, end ) { - - // return closest larger index - // if exact number is not found - - if ( end < start ) - return start; - - var mid = start + Math.floor( ( end - start ) / 2 ); - - if ( cumulativeAreas[ mid ] > value ) { - - return binarySearch( start, mid - 1 ); - - } else if ( cumulativeAreas[ mid ] < value ) { - - return binarySearch( mid + 1, end ); - - } else { - - return mid; - - } - - } - - var result = binarySearch( 0, cumulativeAreas.length - 1 ) - return result; - - } - - // pick random face weighted by face area - - var r, index, - result = []; - - var stats = {}; - - for ( i = 0; i < n; i ++ ) { - - r = THREE.Math.random16() * totalArea; - - index = binarySearchIndices( r ); - - result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true ); - - if ( ! stats[ index ] ) { - - stats[ index ] = 1; - - } else { - - stats[ index ] += 1; - - } - - } - - return result; - - }, - - // Get triangle area (half of parallelogram) - // http://mathworld.wolfram.com/TriangleArea.html - - triangleArea: function () { - - var vector1 = new THREE.Vector3(); - var vector2 = new THREE.Vector3(); - - return function ( vectorA, vectorB, vectorC ) { - - vector1.subVectors( vectorB, vectorA ); - vector2.subVectors( vectorC, vectorA ); - vector1.cross( vector2 ); - - return 0.5 * vector1.length(); - - }; - - }(), - - // Center geometry so that 0,0,0 is in center of bounding box - - center: function ( geometry ) { - - geometry.computeBoundingBox(); - - var bb = geometry.boundingBox; - - var offset = new THREE.Vector3(); - - offset.addVectors( bb.min, bb.max ); - offset.multiplyScalar( -0.5 ); - - geometry.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) ); - geometry.computeBoundingBox(); - - return offset; - - }, - - triangulateQuads: function ( geometry ) { - - var i, il, j, jl; - - var faces = []; - var faceVertexUvs = []; - - for ( i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) { - - faceVertexUvs[ i ] = []; - - } - - for ( i = 0, il = geometry.faces.length; i < il; i ++ ) { - - var face = geometry.faces[ i ]; - - faces.push( face ); - - for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) { - - faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] ); - - } - - } - - geometry.faces = faces; - geometry.faceVertexUvs = faceVertexUvs; - - geometry.computeCentroids(); - geometry.computeFaceNormals(); - geometry.computeVertexNormals(); - - if ( geometry.hasTangents ) geometry.computeTangents(); - - } - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.ImageUtils = { - - crossOrigin: undefined, - - loadTexture: function ( url, mapping, onLoad, onError ) { - - var loader = new THREE.ImageLoader(); - loader.crossOrigin = this.crossOrigin; - - var texture = new THREE.Texture( undefined, mapping ); - - var image = loader.load( url, function () { - - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - } ); - - texture.image = image; - texture.sourceFile = url; - - return texture; - - }, - - loadCompressedTexture: function ( url, mapping, onLoad, onError ) { - - var texture = new THREE.CompressedTexture(); - texture.mapping = mapping; - - var request = new XMLHttpRequest(); - - request.onload = function () { - - var buffer = request.response; - var dds = THREE.ImageUtils.parseDDS( buffer, true ); - - texture.format = dds.format; - - texture.mipmaps = dds.mipmaps; - texture.image.width = dds.width; - texture.image.height = dds.height; - - // gl.generateMipmap fails for compressed textures - // mipmaps must be embedded in the DDS file - // or texture filters must not use mipmapping - - texture.generateMipmaps = false; - - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - } - - request.onerror = onError; - - request.open( 'GET', url, true ); - request.responseType = "arraybuffer"; - request.send( null ); - - return texture; - - }, - - loadTextureCube: function ( array, mapping, onLoad, onError ) { - - var images = []; - images.loadCount = 0; - - var texture = new THREE.Texture(); - texture.image = images; - if ( mapping !== undefined ) texture.mapping = mapping; - - // no flipping needed for cube textures - - texture.flipY = false; - - for ( var i = 0, il = array.length; i < il; ++ i ) { - - var cubeImage = new Image(); - images[ i ] = cubeImage; - - cubeImage.onload = function () { - - images.loadCount += 1; - - if ( images.loadCount === 6 ) { - - texture.needsUpdate = true; - if ( onLoad ) onLoad( texture ); - - } - - }; - - cubeImage.onerror = onError; - - cubeImage.crossOrigin = this.crossOrigin; - cubeImage.src = array[ i ]; - - } - - return texture; - - }, - - loadCompressedTextureCube: function ( array, mapping, onLoad, onError ) { - - var images = []; - images.loadCount = 0; - - var texture = new THREE.CompressedTexture(); - texture.image = images; - if ( mapping !== undefined ) texture.mapping = mapping; - - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) - - texture.flipY = false; - - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files - - texture.generateMipmaps = false; - - var generateCubeFaceCallback = function ( rq, img ) { - - return function () { - - var buffer = rq.response; - var dds = THREE.ImageUtils.parseDDS( buffer, true ); - - img.format = dds.format; - - img.mipmaps = dds.mipmaps; - img.width = dds.width; - img.height = dds.height; - - images.loadCount += 1; - - if ( images.loadCount === 6 ) { - - texture.format = dds.format; - texture.needsUpdate = true; - if ( onLoad ) onLoad( texture ); - - } - - } - - } - - // compressed cubemap textures as 6 separate DDS files - - if ( array instanceof Array ) { - - for ( var i = 0, il = array.length; i < il; ++ i ) { - - var cubeImage = {}; - images[ i ] = cubeImage; - - var request = new XMLHttpRequest(); - - request.onload = generateCubeFaceCallback( request, cubeImage ); - request.onerror = onError; - - var url = array[ i ]; - - request.open( 'GET', url, true ); - request.responseType = "arraybuffer"; - request.send( null ); - - } - - // compressed cubemap texture stored in a single DDS file - - } else { - - var url = array; - var request = new XMLHttpRequest(); - - request.onload = function( ) { - - var buffer = request.response; - var dds = THREE.ImageUtils.parseDDS( buffer, true ); - - if ( dds.isCubemap ) { - - var faces = dds.mipmaps.length / dds.mipmapCount; - - for ( var f = 0; f < faces; f ++ ) { - - images[ f ] = { mipmaps : [] }; - - for ( var i = 0; i < dds.mipmapCount; i ++ ) { - - images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] ); - images[ f ].format = dds.format; - images[ f ].width = dds.width; - images[ f ].height = dds.height; - - } - - } - - texture.format = dds.format; - texture.needsUpdate = true; - if ( onLoad ) onLoad( texture ); - - } - - } - - request.onerror = onError; - - request.open( 'GET', url, true ); - request.responseType = "arraybuffer"; - request.send( null ); - - } - - return texture; - - }, - - loadDDSTexture: function ( url, mapping, onLoad, onError ) { - - var images = []; - images.loadCount = 0; - - var texture = new THREE.CompressedTexture(); - texture.image = images; - if ( mapping !== undefined ) texture.mapping = mapping; - - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) - - texture.flipY = false; - - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files - - texture.generateMipmaps = false; - - { - var request = new XMLHttpRequest(); - - request.onload = function( ) { - - var buffer = request.response; - var dds = THREE.ImageUtils.parseDDS( buffer, true ); - - if ( dds.isCubemap ) { - - var faces = dds.mipmaps.length / dds.mipmapCount; - - for ( var f = 0; f < faces; f ++ ) { - - images[ f ] = { mipmaps : [] }; - - for ( var i = 0; i < dds.mipmapCount; i ++ ) { - - images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] ); - images[ f ].format = dds.format; - images[ f ].width = dds.width; - images[ f ].height = dds.height; - - } - - } - - - } else { - texture.image.width = dds.width; - texture.image.height = dds.height; - texture.mipmaps = dds.mipmaps; - } - - texture.format = dds.format; - texture.needsUpdate = true; - if ( onLoad ) onLoad( texture ); - - } - - request.onerror = onError; - - request.open( 'GET', url, true ); - request.responseType = "arraybuffer"; - request.send( null ); - - } - - return texture; - - }, - - parseDDS: function ( buffer, loadMipmaps ) { - - var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 }; - - // Adapted from @toji's DDS utils - // https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js - - // All values and structures referenced from: - // http://msdn.microsoft.com/en-us/library/bb943991.aspx/ - - var DDS_MAGIC = 0x20534444; - - var DDSD_CAPS = 0x1, - DDSD_HEIGHT = 0x2, - DDSD_WIDTH = 0x4, - DDSD_PITCH = 0x8, - DDSD_PIXELFORMAT = 0x1000, - DDSD_MIPMAPCOUNT = 0x20000, - DDSD_LINEARSIZE = 0x80000, - DDSD_DEPTH = 0x800000; - - var DDSCAPS_COMPLEX = 0x8, - DDSCAPS_MIPMAP = 0x400000, - DDSCAPS_TEXTURE = 0x1000; - - var DDSCAPS2_CUBEMAP = 0x200, - DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, - DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, - DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, - DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, - DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, - DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, - DDSCAPS2_VOLUME = 0x200000; - - var DDPF_ALPHAPIXELS = 0x1, - DDPF_ALPHA = 0x2, - DDPF_FOURCC = 0x4, - DDPF_RGB = 0x40, - DDPF_YUV = 0x200, - DDPF_LUMINANCE = 0x20000; - - function fourCCToInt32( value ) { - - return value.charCodeAt(0) + - (value.charCodeAt(1) << 8) + - (value.charCodeAt(2) << 16) + - (value.charCodeAt(3) << 24); - - } - - function int32ToFourCC( value ) { - - return String.fromCharCode( - value & 0xff, - (value >> 8) & 0xff, - (value >> 16) & 0xff, - (value >> 24) & 0xff - ); - } - - function loadARGBMip( buffer, dataOffset, width, height ) { - var dataLength = width*height*4; - var srcBuffer = new Uint8Array( buffer, dataOffset, dataLength ); - var byteArray = new Uint8Array( dataLength ); - var dst = 0; - var src = 0; - for ( var y = 0; y < height; y++ ) { - for ( var x = 0; x < width; x++ ) { - var b = srcBuffer[src]; src++; - var g = srcBuffer[src]; src++; - var r = srcBuffer[src]; src++; - var a = srcBuffer[src]; src++; - byteArray[dst] = r; dst++; //r - byteArray[dst] = g; dst++; //g - byteArray[dst] = b; dst++; //b - byteArray[dst] = a; dst++; //a - } - } - return byteArray; - } - - var FOURCC_DXT1 = fourCCToInt32("DXT1"); - var FOURCC_DXT3 = fourCCToInt32("DXT3"); - var FOURCC_DXT5 = fourCCToInt32("DXT5"); - - var headerLengthInt = 31; // The header length in 32 bit ints - - // Offsets into the header array - - var off_magic = 0; - - var off_size = 1; - var off_flags = 2; - var off_height = 3; - var off_width = 4; - - var off_mipmapCount = 7; - - var off_pfFlags = 20; - var off_pfFourCC = 21; - var off_RGBBitCount = 22; - var off_RBitMask = 23; - var off_GBitMask = 24; - var off_BBitMask = 25; - var off_ABitMask = 26; - - var off_caps = 27; - var off_caps2 = 28; - var off_caps3 = 29; - var off_caps4 = 30; - - // Parse header - - var header = new Int32Array( buffer, 0, headerLengthInt ); - - if ( header[ off_magic ] !== DDS_MAGIC ) { - - THREE.onerror( "ImageUtils.parseDDS(): Invalid magic number in DDS header" ); - return dds; - - } - - if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) { - - THREE.onerror( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" ); - return dds; - - } - - var blockBytes; - - var fourCC = header[ off_pfFourCC ]; - - var isRGBAUncompressed = false; - - switch ( fourCC ) { - - case FOURCC_DXT1: - - blockBytes = 8; - dds.format = THREE.RGB_S3TC_DXT1_Format; - break; - - case FOURCC_DXT3: - - blockBytes = 16; - dds.format = THREE.RGBA_S3TC_DXT3_Format; - break; - - case FOURCC_DXT5: - - blockBytes = 16; - dds.format = THREE.RGBA_S3TC_DXT5_Format; - break; - - default: - - if( header[off_RGBBitCount] ==32 - && header[off_RBitMask]&0xff0000 - && header[off_GBitMask]&0xff00 - && header[off_BBitMask]&0xff - && header[off_ABitMask]&0xff000000 ) { - isRGBAUncompressed = true; - blockBytes = 64; - dds.format = THREE.RGBAFormat; - } else { - THREE.onerror( "ImageUtils.parseDDS(): Unsupported FourCC code: ", int32ToFourCC( fourCC ) ); - return dds; - } - } - - dds.mipmapCount = 1; - - if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) { - - dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] ); - - } - - //TODO: Verify that all faces of the cubemap are present with DDSCAPS2_CUBEMAP_POSITIVEX, etc. - - dds.isCubemap = header[ off_caps2 ] & DDSCAPS2_CUBEMAP ? true : false; - - dds.width = header[ off_width ]; - dds.height = header[ off_height ]; - - var dataOffset = header[ off_size ] + 4; - - // Extract mipmaps buffers - - var width = dds.width; - var height = dds.height; - - var faces = dds.isCubemap ? 6 : 1; - - for ( var face = 0; face < faces; face ++ ) { - - for ( var i = 0; i < dds.mipmapCount; i ++ ) { - - if( isRGBAUncompressed ) { - var byteArray = loadARGBMip( buffer, dataOffset, width, height ); - var dataLength = byteArray.length; - } else { - var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes; - var byteArray = new Uint8Array( buffer, dataOffset, dataLength ); - } - - var mipmap = { "data": byteArray, "width": width, "height": height }; - dds.mipmaps.push( mipmap ); - - dataOffset += dataLength; - - width = Math.max( width * 0.5, 1 ); - height = Math.max( height * 0.5, 1 ); - - } - - width = dds.width; - height = dds.height; - - } - - return dds; - - }, - - getNormalMap: function ( image, depth ) { - - // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/ - - var cross = function ( a, b ) { - - return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ]; - - } - - var subtract = function ( a, b ) { - - return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ]; - - } - - var normalize = function ( a ) { - - var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] ); - return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ]; - - } - - depth = depth | 1; - - var width = image.width; - var height = image.height; - - var canvas = document.createElement( 'canvas' ); - canvas.width = width; - canvas.height = height; - - var context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0 ); - - var data = context.getImageData( 0, 0, width, height ).data; - var imageData = context.createImageData( width, height ); - var output = imageData.data; - - for ( var x = 0; x < width; x ++ ) { - - for ( var y = 0; y < height; y ++ ) { - - var ly = y - 1 < 0 ? 0 : y - 1; - var uy = y + 1 > height - 1 ? height - 1 : y + 1; - var lx = x - 1 < 0 ? 0 : x - 1; - var ux = x + 1 > width - 1 ? width - 1 : x + 1; - - var points = []; - var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ]; - points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] ); - points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] ); - points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] ); - points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] ); - points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] ); - points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] ); - points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] ); - points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] ); - - var normals = []; - var num_points = points.length; - - for ( var i = 0; i < num_points; i ++ ) { - - var v1 = points[ i ]; - var v2 = points[ ( i + 1 ) % num_points ]; - v1 = subtract( v1, origin ); - v2 = subtract( v2, origin ); - normals.push( normalize( cross( v1, v2 ) ) ); - - } - - var normal = [ 0, 0, 0 ]; - - for ( var i = 0; i < normals.length; i ++ ) { - - normal[ 0 ] += normals[ i ][ 0 ]; - normal[ 1 ] += normals[ i ][ 1 ]; - normal[ 2 ] += normals[ i ][ 2 ]; - - } - - normal[ 0 ] /= normals.length; - normal[ 1 ] /= normals.length; - normal[ 2 ] /= normals.length; - - var idx = ( y * width + x ) * 4; - - output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0; - output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0; - output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0; - output[ idx + 3 ] = 255; - - } - - } - - context.putImageData( imageData, 0, 0 ); - - return canvas; - - }, - - generateDataTexture: function ( width, height, color ) { - - var size = width * height; - var data = new Uint8Array( 3 * size ); - - var r = Math.floor( color.r * 255 ); - var g = Math.floor( color.g * 255 ); - var b = Math.floor( color.b * 255 ); - - for ( var i = 0; i < size; i ++ ) { - - data[ i * 3 ] = r; - data[ i * 3 + 1 ] = g; - data[ i * 3 + 2 ] = b; - - } - - var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat ); - texture.needsUpdate = true; - - return texture; - - } - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.SceneUtils = { - - createMultiMaterialObject: function ( geometry, materials ) { - - var group = new THREE.Object3D(); - - for ( var i = 0, l = materials.length; i < l; i ++ ) { - - group.add( new THREE.Mesh( geometry, materials[ i ] ) ); - - } - - return group; - - }, - - detach : function ( child, parent, scene ) { - - child.applyMatrix( parent.matrixWorld ); - parent.remove( child ); - scene.add( child ); - - }, - - attach: function ( child, scene, parent ) { - - var matrixWorldInverse = new THREE.Matrix4(); - matrixWorldInverse.getInverse( parent.matrixWorld ); - child.applyMatrix( matrixWorldInverse ); - - scene.remove( child ); - parent.add( child ); - - } - -}; - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author alteredq / http://alteredqualia.com/ - * - * For Text operations in three.js (See TextGeometry) - * - * It uses techniques used in: - * - * typeface.js and canvastext - * For converting fonts and rendering with javascript - * http://typeface.neocracy.org - * - * Triangulation ported from AS3 - * Simple Polygon Triangulation - * http://actionsnippet.com/?p=1462 - * - * A Method to triangulate shapes with holes - * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/ - * - */ - -THREE.FontUtils = { - - faces : {}, - - // Just for now. face[weight][style] - - face : "helvetiker", - weight: "normal", - style : "normal", - size : 150, - divisions : 10, - - getFace : function() { - - return this.faces[ this.face ][ this.weight ][ this.style ]; - - }, - - loadFace : function( data ) { - - var family = data.familyName.toLowerCase(); - - var ThreeFont = this; - - ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {}; - - ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {}; - ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; - - var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; - - return data; - - }, - - drawText : function( text ) { - - var characterPts = [], allPts = []; - - // RenderText - - var i, p, - face = this.getFace(), - scale = this.size / face.resolution, - offset = 0, - chars = String( text ).split( '' ), - length = chars.length; - - var fontPaths = []; - - for ( i = 0; i < length; i ++ ) { - - var path = new THREE.Path(); - - var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path ); - offset += ret.offset; - - fontPaths.push( ret.path ); - - } - - // get the width - - var width = offset / 2; - // - // for ( p = 0; p < allPts.length; p++ ) { - // - // allPts[ p ].x -= width; - // - // } - - //var extract = this.extractPoints( allPts, characterPts ); - //extract.contour = allPts; - - //extract.paths = fontPaths; - //extract.offset = width; - - return { paths : fontPaths, offset : width }; - - }, - - - - - extractGlyphPoints : function( c, face, scale, offset, path ) { - - var pts = []; - - var i, i2, divisions, - outline, action, length, - scaleX, scaleY, - x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, - laste, - glyph = face.glyphs[ c ] || face.glyphs[ '?' ]; - - if ( !glyph ) return; - - if ( glyph.o ) { - - outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); - length = outline.length; - - scaleX = scale; - scaleY = scale; - - for ( i = 0; i < length; ) { - - action = outline[ i ++ ]; - - //console.log( action ); - - switch( action ) { - - case 'm': - - // Move To - - x = outline[ i++ ] * scaleX + offset; - y = outline[ i++ ] * scaleY; - - path.moveTo( x, y ); - break; - - case 'l': - - // Line To - - x = outline[ i++ ] * scaleX + offset; - y = outline[ i++ ] * scaleY; - path.lineTo(x,y); - break; - - case 'q': - - // QuadraticCurveTo - - cpx = outline[ i++ ] * scaleX + offset; - cpy = outline[ i++ ] * scaleY; - cpx1 = outline[ i++ ] * scaleX + offset; - cpy1 = outline[ i++ ] * scaleY; - - path.quadraticCurveTo(cpx1, cpy1, cpx, cpy); - - laste = pts[ pts.length - 1 ]; - - if ( laste ) { - - cpx0 = laste.x; - cpy0 = laste.y; - - for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { - - var t = i2 / divisions; - var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); - var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); - } - - } - - break; - - case 'b': - - // Cubic Bezier Curve - - cpx = outline[ i++ ] * scaleX + offset; - cpy = outline[ i++ ] * scaleY; - cpx1 = outline[ i++ ] * scaleX + offset; - cpy1 = outline[ i++ ] * -scaleY; - cpx2 = outline[ i++ ] * scaleX + offset; - cpy2 = outline[ i++ ] * -scaleY; - - path.bezierCurveTo( cpx, cpy, cpx1, cpy1, cpx2, cpy2 ); - - laste = pts[ pts.length - 1 ]; - - if ( laste ) { - - cpx0 = laste.x; - cpy0 = laste.y; - - for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { - - var t = i2 / divisions; - var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); - var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); - - } - - } - - break; - - } - - } - } - - - - return { offset: glyph.ha*scale, path:path}; - } - -}; - - -THREE.FontUtils.generateShapes = function( text, parameters ) { - - // Parameters - - parameters = parameters || {}; - - var size = parameters.size !== undefined ? parameters.size : 100; - var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4; - - var font = parameters.font !== undefined ? parameters.font : "helvetiker"; - var weight = parameters.weight !== undefined ? parameters.weight : "normal"; - var style = parameters.style !== undefined ? parameters.style : "normal"; - - THREE.FontUtils.size = size; - THREE.FontUtils.divisions = curveSegments; - - THREE.FontUtils.face = font; - THREE.FontUtils.weight = weight; - THREE.FontUtils.style = style; - - // Get a Font data json object - - var data = THREE.FontUtils.drawText( text ); - - var paths = data.paths; - var shapes = []; - - for ( var p = 0, pl = paths.length; p < pl; p ++ ) { - - Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); - - } - - return shapes; - -}; - - -/** - * This code is a quick port of code written in C++ which was submitted to - * flipcode.com by John W. Ratcliff // July 22, 2000 - * See original code and more information here: - * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml - * - * ported to actionscript by Zevan Rosser - * www.actionsnippet.com - * - * ported to javascript by Joshua Koo - * http://www.lab4games.net/zz85/blog - * - */ - - -( function( namespace ) { - - var EPSILON = 0.0000000001; - - // takes in an contour array and returns - - var process = function( contour, indices ) { - - var n = contour.length; - - if ( n < 3 ) return null; - - var result = [], - verts = [], - vertIndices = []; - - /* we want a counter-clockwise polygon in verts */ - - var u, v, w; - - if ( area( contour ) > 0.0 ) { - - for ( v = 0; v < n; v++ ) verts[ v ] = v; - - } else { - - for ( v = 0; v < n; v++ ) verts[ v ] = ( n - 1 ) - v; - - } - - var nv = n; - - /* remove nv - 2 vertices, creating 1 triangle every time */ - - var count = 2 * nv; /* error detection */ - - for( v = nv - 1; nv > 2; ) { - - /* if we loop, it is probably a non-simple polygon */ - - if ( ( count-- ) <= 0 ) { - - //** Triangulate: ERROR - probable bad polygon! - - // Sometimes warning is fine, especially polygons are triangulated in reverse. - THREE.onwarning( "Warning, unable to triangulate polygon!" ); - - if ( indices ) return vertIndices; - return result; - - } - - /* three consecutive vertices in current polygon, */ - - u = v; if ( nv <= u ) u = 0; /* previous */ - v = u + 1; if ( nv <= v ) v = 0; /* new v */ - w = v + 1; if ( nv <= w ) w = 0; /* next */ - - if ( snip( contour, u, v, w, nv, verts ) ) { - - var a, b, c, s, t; - - /* true names of the vertices */ - - a = verts[ u ]; - b = verts[ v ]; - c = verts[ w ]; - - /* output Triangle */ - - result.push( [ contour[ a ], - contour[ b ], - contour[ c ] ] ); - - - vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] ); - - /* remove v from the remaining polygon */ - - for( s = v, t = v + 1; t < nv; s++, t++ ) { - - verts[ s ] = verts[ t ]; - - } - - nv--; - - /* reset error detection counter */ - - count = 2 * nv; - - } - - } - - if ( indices ) return vertIndices; - return result; - - }; - - // calculate area of the contour polygon - - var area = function ( contour ) { - - var n = contour.length; - var a = 0.0; - - for( var p = n - 1, q = 0; q < n; p = q++ ) { - - a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; - - } - - return a * 0.5; - - }; - - var snip = function ( contour, u, v, w, n, verts ) { - - var p; - var ax, ay, bx, by; - var cx, cy, px, py; - - ax = contour[ verts[ u ] ].x; - ay = contour[ verts[ u ] ].y; - - bx = contour[ verts[ v ] ].x; - by = contour[ verts[ v ] ].y; - - cx = contour[ verts[ w ] ].x; - cy = contour[ verts[ w ] ].y; - - if ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false; - - var aX, aY, bX, bY, cX, cY; - var apx, apy, bpx, bpy, cpx, cpy; - var cCROSSap, bCROSScp, aCROSSbp; - - aX = cx - bx; aY = cy - by; - bX = ax - cx; bY = ay - cy; - cX = bx - ax; cY = by - ay; - - for ( p = 0; p < n; p++ ) { - - px = contour[ verts[ p ] ].x - py = contour[ verts[ p ] ].y - - if ( ( (px === ax) && (py === ay) ) || - ( (px === bx) && (py === by) ) || - ( (px === cx) && (py === cy) ) ) continue; - - apx = px - ax; apy = py - ay; - bpx = px - bx; bpy = py - by; - cpx = px - cx; cpy = py - cy; - - // see if p is inside triangle abc - - aCROSSbp = aX*bpy - aY*bpx; - cCROSSap = cX*apy - cY*apx; - bCROSScp = bX*cpy - bY*cpx; - - if ( (aCROSSbp >= -EPSILON) && (bCROSScp >= -EPSILON) && (cCROSSap >= -EPSILON) ) return false; - - } - - return true; - - }; - - - namespace.Triangulate = process; - namespace.Triangulate.area = area; - - return namespace; - -})(THREE.FontUtils); - -// To use the typeface.js face files, hook up the API -self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace }; -THREE.typeface_js = self._typeface_js; - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Extensible curve object - * - * Some common of Curve methods - * .getPoint(t), getTangent(t) - * .getPointAt(u), getTagentAt(u) - * .getPoints(), .getSpacedPoints() - * .getLength() - * .updateArcLengths() - * - * This following classes subclasses THREE.Curve: - * - * -- 2d classes -- - * THREE.LineCurve - * THREE.QuadraticBezierCurve - * THREE.CubicBezierCurve - * THREE.SplineCurve - * THREE.ArcCurve - * THREE.EllipseCurve - * - * -- 3d classes -- - * THREE.LineCurve3 - * THREE.QuadraticBezierCurve3 - * THREE.CubicBezierCurve3 - * THREE.SplineCurve3 - * THREE.ClosedSplineCurve3 - * - * A series of curves can be represented as a THREE.CurvePath - * - **/ - -/************************************************************** - * Abstract Curve base class - **************************************************************/ - -THREE.Curve = function () { - -}; - -// Virtual base class method to overwrite and implement in subclasses -// - t [0 .. 1] - -THREE.Curve.prototype.getPoint = function ( t ) { - - THREE.onwarning( "Warning, getPoint() not implemented!" ); - return null; - -}; - -// Get point at relative position in curve according to arc length -// - u [0 .. 1] - -THREE.Curve.prototype.getPointAt = function ( u ) { - - var t = this.getUtoTmapping( u ); - return this.getPoint( t ); - -}; - -// Get sequence of points using getPoint( t ) - -THREE.Curve.prototype.getPoints = function ( divisions ) { - - if ( !divisions ) divisions = 5; - - var d, pts = []; - - for ( d = 0; d <= divisions; d ++ ) { - - pts.push( this.getPoint( d / divisions ) ); - - } - - return pts; - -}; - -// Get sequence of points using getPointAt( u ) - -THREE.Curve.prototype.getSpacedPoints = function ( divisions ) { - - if ( !divisions ) divisions = 5; - - var d, pts = []; - - for ( d = 0; d <= divisions; d ++ ) { - - pts.push( this.getPointAt( d / divisions ) ); - - } - - return pts; - -}; - -// Get total curve arc length - -THREE.Curve.prototype.getLength = function () { - - var lengths = this.getLengths(); - return lengths[ lengths.length - 1 ]; - -}; - -// Get list of cumulative segment lengths - -THREE.Curve.prototype.getLengths = function ( divisions ) { - - if ( !divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200; - - if ( this.cacheArcLengths - && ( this.cacheArcLengths.length == divisions + 1 ) - && !this.needsUpdate) { - - //console.log( "cached", this.cacheArcLengths ); - return this.cacheArcLengths; - - } - - this.needsUpdate = false; - - var cache = []; - var current, last = this.getPoint( 0 ); - var p, sum = 0; - - cache.push( 0 ); - - for ( p = 1; p <= divisions; p ++ ) { - - current = this.getPoint ( p / divisions ); - sum += current.distanceTo( last ); - cache.push( sum ); - last = current; - - } - - this.cacheArcLengths = cache; - - return cache; // { sums: cache, sum:sum }; Sum is in the last element. - -}; - - -THREE.Curve.prototype.updateArcLengths = function() { - this.needsUpdate = true; - this.getLengths(); -}; - -// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance - -THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) { - - var arcLengths = this.getLengths(); - - var i = 0, il = arcLengths.length; - - var targetArcLength; // The targeted u distance value to get - - if ( distance ) { - - targetArcLength = distance; - - } else { - - targetArcLength = u * arcLengths[ il - 1 ]; - - } - - //var time = Date.now(); - - // binary search for the index with largest value smaller than target u distance - - var low = 0, high = il - 1, comparison; - - while ( low <= high ) { - - 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 - - comparison = arcLengths[ i ] - targetArcLength; - - if ( comparison < 0 ) { - - low = i + 1; - continue; - - } else if ( comparison > 0 ) { - - high = i - 1; - continue; - - } else { - - high = i; - break; - - // DONE - - } - - } - - i = high; - - //console.log('b' , i, low, high, Date.now()- time); - - if ( arcLengths[ i ] == targetArcLength ) { - - var t = i / ( il - 1 ); - return t; - - } - - // we could get finer grain at lengths, or use simple interpolatation between two points - - var lengthBefore = arcLengths[ i ]; - var lengthAfter = arcLengths[ i + 1 ]; - - var segmentLength = lengthAfter - lengthBefore; - - // determine where we are between the 'before' and 'after' points - - var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; - - // add that fractional amount to t - - var t = ( i + segmentFraction ) / ( il -1 ); - - return t; - -}; - -// Returns a unit vector tangent at t -// In case any sub curve does not implement its tangent derivation, -// 2 points a small delta apart will be used to find its gradient -// which seems to give a reasonable approximation - -THREE.Curve.prototype.getTangent = function( t ) { - - var delta = 0.0001; - var t1 = t - delta; - var t2 = t + delta; - - // Capping in case of danger - - if ( t1 < 0 ) t1 = 0; - if ( t2 > 1 ) t2 = 1; - - var pt1 = this.getPoint( t1 ); - var pt2 = this.getPoint( t2 ); - - var vec = pt2.clone().sub(pt1); - return vec.normalize(); - -}; - - -THREE.Curve.prototype.getTangentAt = function ( u ) { - - var t = this.getUtoTmapping( u ); - return this.getTangent( t ); - -}; - - - - - -/************************************************************** - * Utils - **************************************************************/ - -THREE.Curve.Utils = { - - tangentQuadraticBezier: function ( t, p0, p1, p2 ) { - - return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ); - - }, - - // Puay Bing, thanks for helping with this derivative! - - tangentCubicBezier: function (t, p0, p1, p2, p3 ) { - - return -3 * p0 * (1 - t) * (1 - t) + - 3 * p1 * (1 - t) * (1-t) - 6 *t *p1 * (1-t) + - 6 * t * p2 * (1-t) - 3 * t * t * p2 + - 3 * t * t * p3; - }, - - - tangentSpline: function ( t, p0, p1, p2, p3 ) { - - // To check if my formulas are correct - - var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1 - var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t - var h01 = -6 * t * t + 6 * t; // − 2t3 + 3t2 - var h11 = 3 * t * t - 2 * t; // t3 − t2 - - return h00 + h10 + h01 + h11; - - }, - - // Catmull-Rom - - interpolate: function( p0, p1, p2, p3, t ) { - - var v0 = ( p2 - p0 ) * 0.5; - var v1 = ( p3 - p1 ) * 0.5; - var t2 = t * t; - var t3 = t * t2; - return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; - - } - -}; - - -// TODO: Transformation for Curves? - -/************************************************************** - * 3D Curves - **************************************************************/ - -// A Factory method for creating new curve subclasses - -THREE.Curve.create = function ( constructor, getPointFunc ) { - - constructor.prototype = Object.create( THREE.Curve.prototype ); - constructor.prototype.getPoint = getPointFunc; - - return constructor; - -}; - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - **/ - -/************************************************************** - * Curved Path - a curve path is simply a array of connected - * curves, but retains the api of a curve - **************************************************************/ - -THREE.CurvePath = function () { - - this.curves = []; - this.bends = []; - - this.autoClose = false; // Automatically closes the path -}; - -THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype ); - -THREE.CurvePath.prototype.add = function ( curve ) { - - this.curves.push( curve ); - -}; - -THREE.CurvePath.prototype.checkConnection = function() { - // TODO - // If the ending of curve is not connected to the starting - // or the next curve, then, this is not a real path -}; - -THREE.CurvePath.prototype.closePath = function() { - // TODO Test - // and verify for vector3 (needs to implement equals) - // Add a line curve if start and end of lines are not connected - var startPoint = this.curves[0].getPoint(0); - var endPoint = this.curves[this.curves.length-1].getPoint(1); - - if (!startPoint.equals(endPoint)) { - this.curves.push( new THREE.LineCurve(endPoint, startPoint) ); - } - -}; - -// To get accurate point with reference to -// entire path distance at time t, -// following has to be done: - -// 1. Length of each sub path have to be known -// 2. Locate and identify type of curve -// 3. Get t for the curve -// 4. Return curve.getPointAt(t') - -THREE.CurvePath.prototype.getPoint = function( t ) { - - var d = t * this.getLength(); - var curveLengths = this.getCurveLengths(); - var i = 0, diff, curve; - - // To think about boundaries points. - - while ( i < curveLengths.length ) { - - if ( curveLengths[ i ] >= d ) { - - diff = curveLengths[ i ] - d; - curve = this.curves[ i ]; - - var u = 1 - diff / curve.getLength(); - - return curve.getPointAt( u ); - - break; - } - - i ++; - - } - - return null; - - // loop where sum != 0, sum > d , sum+1 maxX ) maxX = p.x; - else if ( p.x < minX ) minX = p.x; - - if ( p.y > maxY ) maxY = p.y; - else if ( p.y < minY ) minY = p.y; - - if ( v3 ) { - - if ( p.z > maxZ ) maxZ = p.z; - else if ( p.z < minZ ) minZ = p.z; - - } - - sum.add( p ); - - } - - var ret = { - - minX: minX, - minY: minY, - maxX: maxX, - maxY: maxY, - centroid: sum.divideScalar( il ) - - }; - - if ( v3 ) { - - ret.maxZ = maxZ; - ret.minZ = minZ; - - } - - return ret; - -}; - -/************************************************************** - * Create Geometries Helpers - **************************************************************/ - -/// Generate geometry from path points (for Line or ParticleSystem objects) - -THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) { - - var pts = this.getPoints( divisions, true ); - return this.createGeometry( pts ); - -}; - -// Generate geometry from equidistance sampling along the path - -THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) { - - var pts = this.getSpacedPoints( divisions, true ); - return this.createGeometry( pts ); - -}; - -THREE.CurvePath.prototype.createGeometry = function( points ) { - - var geometry = new THREE.Geometry(); - - for ( var i = 0; i < points.length; i ++ ) { - - geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) ); - - } - - return geometry; - -}; - - -/************************************************************** - * Bend / Wrap Helper Methods - **************************************************************/ - -// Wrap path / Bend modifiers? - -THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) { - - this.bends.push( bendpath ); - -}; - -THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) { - - var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints - var i, il; - - if ( !bends ) { - - bends = this.bends; - - } - - for ( i = 0, il = bends.length; i < il; i ++ ) { - - oldPts = this.getWrapPoints( oldPts, bends[ i ] ); - - } - - return oldPts; - -}; - -THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) { - - var oldPts = this.getSpacedPoints( segments ); - - var i, il; - - if ( !bends ) { - - bends = this.bends; - - } - - for ( i = 0, il = bends.length; i < il; i ++ ) { - - oldPts = this.getWrapPoints( oldPts, bends[ i ] ); - - } - - return oldPts; - -}; - -// This returns getPoints() bend/wrapped around the contour of a path. -// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html - -THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) { - - var bounds = this.getBoundingBox(); - - var i, il, p, oldX, oldY, xNorm; - - for ( i = 0, il = oldPts.length; i < il; i ++ ) { - - p = oldPts[ i ]; - - oldX = p.x; - oldY = p.y; - - xNorm = oldX / bounds.maxX; - - // If using actual distance, for length > path, requires line extrusions - //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance - - xNorm = path.getUtoTmapping( xNorm, oldX ); - - // check for out of bounds? - - var pathPt = path.getPoint( xNorm ); - var normal = path.getTangent( xNorm ); - normal.set( -normal.y, normal.x ).multiplyScalar( oldY ); - - p.x = pathPt.x + normal.x; - p.y = pathPt.y + normal.y; - - } - - return oldPts; - -}; - - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Gyroscope = function () { - - THREE.Object3D.call( this ); - -}; - -THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.Gyroscope.prototype.updateMatrixWorld = function ( force ) { - - this.matrixAutoUpdate && this.updateMatrix(); - - // update matrixWorld - - if ( this.matrixWorldNeedsUpdate || force ) { - - if ( this.parent ) { - - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - - this.matrixWorld.decompose( this.translationWorld, this.quaternionWorld, this.scaleWorld ); - this.matrix.decompose( this.translationObject, this.quaternionObject, this.scaleObject ); - - this.matrixWorld.compose( this.translationWorld, this.quaternionObject, this.scaleWorld ); - - - } else { - - this.matrixWorld.copy( this.matrix ); - - } - - - this.matrixWorldNeedsUpdate = false; - - force = true; - - } - - // update children - - for ( var i = 0, l = this.children.length; i < l; i ++ ) { - - this.children[ i ].updateMatrixWorld( force ); - - } - -}; - -THREE.Gyroscope.prototype.translationWorld = new THREE.Vector3(); -THREE.Gyroscope.prototype.translationObject = new THREE.Vector3(); -THREE.Gyroscope.prototype.quaternionWorld = new THREE.Quaternion(); -THREE.Gyroscope.prototype.quaternionObject = new THREE.Quaternion(); -THREE.Gyroscope.prototype.scaleWorld = new THREE.Vector3(); -THREE.Gyroscope.prototype.scaleObject = new THREE.Vector3(); - - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Creates free form 2d path using series of points, lines or curves. - * - **/ - -THREE.Path = function ( points ) { - - THREE.CurvePath.call(this); - - this.actions = []; - - if ( points ) { - - this.fromPoints( points ); - - } - -}; - -THREE.Path.prototype = Object.create( THREE.CurvePath.prototype ); - -THREE.PathActions = { - - MOVE_TO: 'moveTo', - LINE_TO: 'lineTo', - QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve - BEZIER_CURVE_TO: 'bezierCurveTo', // Bezier cubic curve - CSPLINE_THRU: 'splineThru', // Catmull-rom spline - ARC: 'arc', // Circle - ELLIPSE: 'ellipse' -}; - -// TODO Clean up PATH API - -// Create path using straight lines to connect all points -// - vectors: array of Vector2 - -THREE.Path.prototype.fromPoints = function ( vectors ) { - - this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); - - for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) { - - this.lineTo( vectors[ v ].x, vectors[ v ].y ); - - }; - -}; - -// startPath() endPath()? - -THREE.Path.prototype.moveTo = function ( x, y ) { - - var args = Array.prototype.slice.call( arguments ); - this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } ); - -}; - -THREE.Path.prototype.lineTo = function ( x, y ) { - - var args = Array.prototype.slice.call( arguments ); - - var lastargs = this.actions[ this.actions.length - 1 ].args; - - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; - - var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) ); - this.curves.push( curve ); - - this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } ); - -}; - -THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) { - - var args = Array.prototype.slice.call( arguments ); - - var lastargs = this.actions[ this.actions.length - 1 ].args; - - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; - - var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ), - new THREE.Vector2( aCPx, aCPy ), - new THREE.Vector2( aX, aY ) ); - this.curves.push( curve ); - - this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } ); - -}; - -THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, - aCP2x, aCP2y, - aX, aY ) { - - var args = Array.prototype.slice.call( arguments ); - - var lastargs = this.actions[ this.actions.length - 1 ].args; - - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; - - var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ), - new THREE.Vector2( aCP1x, aCP1y ), - new THREE.Vector2( aCP2x, aCP2y ), - new THREE.Vector2( aX, aY ) ); - this.curves.push( curve ); - - this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } ); - -}; - -THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) { - - var args = Array.prototype.slice.call( arguments ); - var lastargs = this.actions[ this.actions.length - 1 ].args; - - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; -//--- - var npts = [ new THREE.Vector2( x0, y0 ) ]; - Array.prototype.push.apply( npts, pts ); - - var curve = new THREE.SplineCurve( npts ); - this.curves.push( curve ); - - this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } ); - -}; - -// FUTURE: Change the API or follow canvas API? - -THREE.Path.prototype.arc = function ( aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise ) { - - var lastargs = this.actions[ this.actions.length - 1].args; - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; - - this.absarc(aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise ); - - }; - - THREE.Path.prototype.absarc = function ( aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise ) { - this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); - }; - -THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ) { - - var lastargs = this.actions[ this.actions.length - 1].args; - var x0 = lastargs[ lastargs.length - 2 ]; - var y0 = lastargs[ lastargs.length - 1 ]; - - this.absellipse(aX + x0, aY + y0, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ); - - }; - - -THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ) { - - var args = Array.prototype.slice.call( arguments ); - var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, - aStartAngle, aEndAngle, aClockwise ); - this.curves.push( curve ); - - var lastPoint = curve.getPoint(1); - args.push(lastPoint.x); - args.push(lastPoint.y); - - this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } ); - - }; - -THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) { - - if ( ! divisions ) divisions = 40; - - var points = []; - - for ( var i = 0; i < divisions; i ++ ) { - - points.push( this.getPoint( i / divisions ) ); - - //if( !this.getPoint( i / divisions ) ) throw "DIE"; - - } - - // if ( closedPath ) { - // - // points.push( points[ 0 ] ); - // - // } - - return points; - -}; - -/* Return an array of vectors based on contour of the path */ - -THREE.Path.prototype.getPoints = function( divisions, closedPath ) { - - if (this.useSpacedPoints) { - console.log('tata'); - return this.getSpacedPoints( divisions, closedPath ); - } - - divisions = divisions || 12; - - var points = []; - - var i, il, item, action, args; - var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, - laste, j, - t, tx, ty; - - for ( i = 0, il = this.actions.length; i < il; i ++ ) { - - item = this.actions[ i ]; - - action = item.action; - args = item.args; - - switch( action ) { - - case THREE.PathActions.MOVE_TO: - - points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); - - break; - - case THREE.PathActions.LINE_TO: - - points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); - - break; - - case THREE.PathActions.QUADRATIC_CURVE_TO: - - cpx = args[ 2 ]; - cpy = args[ 3 ]; - - cpx1 = args[ 0 ]; - cpy1 = args[ 1 ]; - - if ( points.length > 0 ) { - - laste = points[ points.length - 1 ]; - - cpx0 = laste.x; - cpy0 = laste.y; - - } else { - - laste = this.actions[ i - 1 ].args; - - cpx0 = laste[ laste.length - 2 ]; - cpy0 = laste[ laste.length - 1 ]; - - } - - for ( j = 1; j <= divisions; j ++ ) { - - t = j / divisions; - - tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); - ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); - - points.push( new THREE.Vector2( tx, ty ) ); - - } - - break; - - case THREE.PathActions.BEZIER_CURVE_TO: - - cpx = args[ 4 ]; - cpy = args[ 5 ]; - - cpx1 = args[ 0 ]; - cpy1 = args[ 1 ]; - - cpx2 = args[ 2 ]; - cpy2 = args[ 3 ]; - - if ( points.length > 0 ) { - - laste = points[ points.length - 1 ]; - - cpx0 = laste.x; - cpy0 = laste.y; - - } else { - - laste = this.actions[ i - 1 ].args; - - cpx0 = laste[ laste.length - 2 ]; - cpy0 = laste[ laste.length - 1 ]; - - } - - - for ( j = 1; j <= divisions; j ++ ) { - - t = j / divisions; - - tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); - ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); - - points.push( new THREE.Vector2( tx, ty ) ); - - } - - break; - - case THREE.PathActions.CSPLINE_THRU: - - laste = this.actions[ i - 1 ].args; - - var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); - var spts = [ last ]; - - var n = divisions * args[ 0 ].length; - - spts = spts.concat( args[ 0 ] ); - - var spline = new THREE.SplineCurve( spts ); - - for ( j = 1; j <= n; j ++ ) { - - points.push( spline.getPointAt( j / n ) ) ; - - } - - break; - - case THREE.PathActions.ARC: - - var aX = args[ 0 ], aY = args[ 1 ], - aRadius = args[ 2 ], - aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], - aClockwise = !!args[ 5 ]; - - var deltaAngle = aEndAngle - aStartAngle; - var angle; - var tdivisions = divisions * 2; - - for ( j = 1; j <= tdivisions; j ++ ) { - - t = j / tdivisions; - - if ( ! aClockwise ) { - - t = 1 - t; - - } - - angle = aStartAngle + t * deltaAngle; - - tx = aX + aRadius * Math.cos( angle ); - ty = aY + aRadius * Math.sin( angle ); - - //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); - - points.push( new THREE.Vector2( tx, ty ) ); - - } - - //console.log(points); - - break; - - case THREE.PathActions.ELLIPSE: - - var aX = args[ 0 ], aY = args[ 1 ], - xRadius = args[ 2 ], - yRadius = args[ 3 ], - aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], - aClockwise = !!args[ 6 ]; - - - var deltaAngle = aEndAngle - aStartAngle; - var angle; - var tdivisions = divisions * 2; - - for ( j = 1; j <= tdivisions; j ++ ) { - - t = j / tdivisions; - - if ( ! aClockwise ) { - - t = 1 - t; - - } - - angle = aStartAngle + t * deltaAngle; - - tx = aX + xRadius * Math.cos( angle ); - ty = aY + yRadius * Math.sin( angle ); - - //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); - - points.push( new THREE.Vector2( tx, ty ) ); - - } - - //console.log(points); - - break; - - } // end switch - - } - - - - // Normalize to remove the closing point by default. - var lastPoint = points[ points.length - 1]; - var EPSILON = 0.0000000001; - if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON && - Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON) - points.splice( points.length - 1, 1); - if ( closedPath ) { - - points.push( points[ 0 ] ); - - } - - return points; - -}; - -// Breaks path into shapes - -THREE.Path.prototype.toShapes = function( isCCW ) { - - function isPointInsidePolygon( inPt, inPolygon ) { - var EPSILON = 0.0000000001; - - var polyLen = inPolygon.length; - - // inPt on polygon contour => immediate success or - // toggling of inside/outside at every single! intersection point of an edge - // with the horizontal line through inPt, left of inPt - // not counting lowerY endpoints of edges and whole edges on that line - var inside = false; - for( var p = polyLen - 1, q = 0; q < polyLen; p = q++ ) { - var edgeLowPt = inPolygon[ p ]; - var edgeHighPt = inPolygon[ q ]; - - var edgeDx = edgeHighPt.x - edgeLowPt.x; - var edgeDy = edgeHighPt.y - edgeLowPt.y; - - if ( Math.abs(edgeDy) > EPSILON ) { // not parallel - if ( edgeDy < 0 ) { - edgeLowPt = inPolygon[ q ]; edgeDx = -edgeDx; - edgeHighPt = inPolygon[ p ]; edgeDy = -edgeDy; - } - if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; - - if ( inPt.y == edgeLowPt.y ) { - if ( inPt.x == edgeLowPt.x ) return true; // inPt is on contour ? - // continue; // no intersection or edgeLowPt => doesn't count !!! - } else { - var perpEdge = edgeDy * (inPt.x - edgeLowPt.x) - edgeDx * (inPt.y - edgeLowPt.y); - if ( perpEdge == 0 ) return true; // inPt is on contour ? - if ( perpEdge < 0 ) continue; - inside = !inside; // true intersection left of inPt - } - } else { // parallel or colinear - if ( inPt.y != edgeLowPt.y ) continue; // parallel - // egde lies on the same horizontal line as inPt - if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || - ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! - // continue; - } - } - - return inside; - } - - var i, il, item, action, args; - - var subPaths = [], lastPath = new THREE.Path(); - - for ( i = 0, il = this.actions.length; i < il; i ++ ) { - - item = this.actions[ i ]; - - args = item.args; - action = item.action; - - if ( action == THREE.PathActions.MOVE_TO ) { - - if ( lastPath.actions.length != 0 ) { - - subPaths.push( lastPath ); - lastPath = new THREE.Path(); - - } - - } - - lastPath[ action ].apply( lastPath, args ); - - } - - if ( lastPath.actions.length != 0 ) { - - subPaths.push( lastPath ); - - } - - // console.log(subPaths); - - if ( subPaths.length == 0 ) return []; - - var solid, tmpPath, tmpShape, shapes = []; - - if ( subPaths.length == 1) { - - tmpPath = subPaths[0]; - tmpShape = new THREE.Shape(); - tmpShape.actions = tmpPath.actions; - tmpShape.curves = tmpPath.curves; - shapes.push( tmpShape ); - return shapes; - - } - - var holesFirst = !THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() ); - holesFirst = isCCW ? !holesFirst : holesFirst; - - // console.log("Holes first", holesFirst); - - var betterShapeHoles = []; - var newShapes = []; - var newShapeHoles = []; - var mainIdx = 0; - var tmpPoints; - - newShapes[mainIdx] = undefined; - newShapeHoles[mainIdx] = []; - - for ( i = 0, il = subPaths.length; i < il; i ++ ) { - - tmpPath = subPaths[ i ]; - tmpPoints = tmpPath.getPoints(); - solid = THREE.Shape.Utils.isClockWise( tmpPoints ); - solid = isCCW ? !solid : solid; - - if ( solid ) { - - if ( (! holesFirst ) && ( newShapes[mainIdx] ) ) mainIdx++; - - newShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints }; - newShapes[mainIdx].s.actions = tmpPath.actions; - newShapes[mainIdx].s.curves = tmpPath.curves; - - if ( holesFirst ) mainIdx++; - newShapeHoles[mainIdx] = []; - - //console.log('cw', i); - - } else { - - newShapeHoles[mainIdx].push( { h: tmpPath, p: tmpPoints[0] } ); - - //console.log('ccw', i); - - } - - } - - if ( newShapes.length > 1 ) { - var ambigious = false; - var toChange = []; - - for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx++ ) { - betterShapeHoles[sIdx] = []; - } - for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx++ ) { - var sh = newShapes[sIdx]; - var sho = newShapeHoles[sIdx]; - for (var hIdx = 0; hIdx < sho.length; hIdx++ ) { - var ho = sho[hIdx]; - var hole_unassigned = true; - for (var s2Idx = 0; s2Idx < newShapes.length; s2Idx++ ) { - if ( isPointInsidePolygon( ho.p, newShapes[s2Idx].p ) ) { - if ( sIdx != s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } ); - if ( hole_unassigned ) { - hole_unassigned = false; - betterShapeHoles[s2Idx].push( ho ); - } else { - ambigious = true; - } - } - } - if ( hole_unassigned ) { betterShapeHoles[sIdx].push( ho ); } - } - } - // console.log("ambigious: ", ambigious); - if ( toChange.length > 0 ) { - // console.log("to change: ", toChange); - if (! ambigious) newShapeHoles = betterShapeHoles; - } - } - - var tmpHoles, j, jl; - for ( i = 0, il = newShapes.length; i < il; i ++ ) { - tmpShape = newShapes[i].s; - shapes.push( tmpShape ); - tmpHoles = newShapeHoles[i]; - for ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) { - tmpShape.holes.push( tmpHoles[j].h ); - } - } - - //console.log("shape", shapes); - - return shapes; - -}; - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Defines a 2d shape plane using paths. - **/ - -// STEP 1 Create a path. -// STEP 2 Turn path into shape. -// STEP 3 ExtrudeGeometry takes in Shape/Shapes -// STEP 3a - Extract points from each shape, turn to vertices -// STEP 3b - Triangulate each shape, add faces. - -THREE.Shape = function () { - - THREE.Path.apply( this, arguments ); - this.holes = []; - -}; - -THREE.Shape.prototype = Object.create( THREE.Path.prototype ); - -// Convenience method to return ExtrudeGeometry - -THREE.Shape.prototype.extrude = function ( options ) { - - var extruded = new THREE.ExtrudeGeometry( this, options ); - return extruded; - -}; - -// Convenience method to return ShapeGeometry - -THREE.Shape.prototype.makeGeometry = function ( options ) { - - var geometry = new THREE.ShapeGeometry( this, options ); - return geometry; - -}; - -// Get points of holes - -THREE.Shape.prototype.getPointsHoles = function ( divisions ) { - - var i, il = this.holes.length, holesPts = []; - - for ( i = 0; i < il; i ++ ) { - - holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends ); - - } - - return holesPts; - -}; - -// Get points of holes (spaced by regular distance) - -THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) { - - var i, il = this.holes.length, holesPts = []; - - for ( i = 0; i < il; i ++ ) { - - holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends ); - - } - - return holesPts; - -}; - - -// Get points of shape and holes (keypoints based on segments parameter) - -THREE.Shape.prototype.extractAllPoints = function ( divisions ) { - - return { - - shape: this.getTransformedPoints( divisions ), - holes: this.getPointsHoles( divisions ) - - }; - -}; - -THREE.Shape.prototype.extractPoints = function ( divisions ) { - - if (this.useSpacedPoints) { - return this.extractAllSpacedPoints(divisions); - } - - return this.extractAllPoints(divisions); - -}; - -// -// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) { -// -// return { -// -// shape: this.transform( bend, divisions ), -// holes: this.getPointsHoles( divisions, bend ) -// -// }; -// -// }; - -// Get points of shape and holes (spaced by regular distance) - -THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) { - - return { - - shape: this.getTransformedSpacedPoints( divisions ), - holes: this.getSpacedPointsHoles( divisions ) - - }; - -}; - -/************************************************************** - * Utils - **************************************************************/ - -THREE.Shape.Utils = { - - triangulateShape: function ( contour, holes ) { - - function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) { - // inOtherPt needs to be colinear to the inSegment - if ( inSegPt1.x != inSegPt2.x ) { - if ( inSegPt1.x < inSegPt2.x ) { - return ( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) ); - } else { - return ( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) ); - } - } else { - if ( inSegPt1.y < inSegPt2.y ) { - return ( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) ); - } else { - return ( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) ); - } - } - } - - function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) { - var EPSILON = 0.0000000001; - - var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y; - var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y; - - var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x; - var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y; - - var limit = seg1dy * seg2dx - seg1dx * seg2dy; - var perpSeg1 = seg1dy * seg1seg2dx - seg1dx * seg1seg2dy; - - if ( Math.abs(limit) > EPSILON ) { // not parallel - - var perpSeg2; - if ( limit > 0 ) { - if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) return []; - perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; - if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) return []; - } else { - if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) return []; - perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; - if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) return []; - } - - // i.e. to reduce rounding errors - // intersection at endpoint of segment#1? - if ( perpSeg2 == 0 ) { - if ( ( inExcludeAdjacentSegs ) && - ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return []; - return [ inSeg1Pt1 ]; - } - if ( perpSeg2 == limit ) { - if ( ( inExcludeAdjacentSegs ) && - ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return []; - return [ inSeg1Pt2 ]; - } - // intersection at endpoint of segment#2? - if ( perpSeg1 == 0 ) return [ inSeg2Pt1 ]; - if ( perpSeg1 == limit ) return [ inSeg2Pt2 ]; - - // return real intersection point - var factorSeg1 = perpSeg2 / limit; - return [ { x: inSeg1Pt1.x + factorSeg1 * seg1dx, - y: inSeg1Pt1.y + factorSeg1 * seg1dy } ]; - - } else { // parallel or colinear - if ( ( perpSeg1 != 0 ) || - ( seg2dy * seg1seg2dx != seg2dx * seg1seg2dy ) ) return []; - - // they are collinear or degenerate - var seg1Pt = ( (seg1dx == 0) && (seg1dy == 0) ); // segment1 ist just a point? - var seg2Pt = ( (seg2dx == 0) && (seg2dy == 0) ); // segment2 ist just a point? - // both segments are points - if ( seg1Pt && seg2Pt ) { - if ( (inSeg1Pt1.x != inSeg2Pt1.x) || - (inSeg1Pt1.y != inSeg2Pt1.y) ) return []; // they are distinct points - return [ inSeg1Pt1 ]; // they are the same point - } - // segment#1 is a single point - if ( seg1Pt ) { - if (! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) ) return []; // but not in segment#2 - return [ inSeg1Pt1 ]; - } - // segment#2 is a single point - if ( seg2Pt ) { - if (! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) ) return []; // but not in segment#1 - return [ inSeg2Pt1 ]; - } - - // they are collinear segments, which might overlap - var seg1min, seg1max, seg1minVal, seg1maxVal; - var seg2min, seg2max, seg2minVal, seg2maxVal; - if (seg1dx != 0) { // the segments are NOT on a vertical line - if ( inSeg1Pt1.x < inSeg1Pt2.x ) { - seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x; - seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x; - } else { - seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x; - seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x; - } - if ( inSeg2Pt1.x < inSeg2Pt2.x ) { - seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x; - seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x; - } else { - seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x; - seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x; - } - } else { // the segments are on a vertical line - if ( inSeg1Pt1.y < inSeg1Pt2.y ) { - seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y; - seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y; - } else { - seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y; - seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y; - } - if ( inSeg2Pt1.y < inSeg2Pt2.y ) { - seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y; - seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y; - } else { - seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y; - seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y; - } - } - if ( seg1minVal <= seg2minVal ) { - if ( seg1maxVal < seg2minVal ) return []; - if ( seg1maxVal == seg2minVal ) { - if ( inExcludeAdjacentSegs ) return []; - return [ seg2min ]; - } - if ( seg1maxVal <= seg2maxVal ) return [ seg2min, seg1max ]; - return [ seg2min, seg2max ]; - } else { - if ( seg1minVal > seg2maxVal ) return []; - if ( seg1minVal == seg2maxVal ) { - if ( inExcludeAdjacentSegs ) return []; - return [ seg1min ]; - } - if ( seg1maxVal <= seg2maxVal ) return [ seg1min, seg1max ]; - return [ seg1min, seg2max ]; - } - } - } - - function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) { - // The order of legs is important - - var EPSILON = 0.0000000001; - - // translation of all points, so that Vertex is at (0,0) - var legFromPtX = inLegFromPt.x - inVertex.x, legFromPtY = inLegFromPt.y - inVertex.y; - var legToPtX = inLegToPt.x - inVertex.x, legToPtY = inLegToPt.y - inVertex.y; - var otherPtX = inOtherPt.x - inVertex.x, otherPtY = inOtherPt.y - inVertex.y; - - // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg. - var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX; - var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX; - - if ( Math.abs(from2toAngle) > EPSILON ) { // angle != 180 deg. - - var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX; - // console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle ); - - if ( from2toAngle > 0 ) { // main angle < 180 deg. - return ( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) ); - } else { // main angle > 180 deg. - return ( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) ); - } - } else { // angle == 180 deg. - // console.log( "from2to: 180 deg., from2other: " + from2otherAngle ); - return ( from2otherAngle > 0 ); - } - } - - - function removeHoles( contour, holes ) { - - var shape = contour.concat(); // work on this shape - var hole; - - function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) { - // Check if hole point lies within angle around shape point - var lastShapeIdx = shape.length - 1; - - var prevShapeIdx = inShapeIdx - 1; - if ( prevShapeIdx < 0 ) prevShapeIdx = lastShapeIdx; - - var nextShapeIdx = inShapeIdx + 1; - if ( nextShapeIdx > lastShapeIdx ) nextShapeIdx = 0; - - var insideAngle = isPointInsideAngle( shape[inShapeIdx], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[inHoleIdx] ); - if (! insideAngle ) { - // console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y ); - return false; - } - - // Check if shape point lies within angle around hole point - var lastHoleIdx = hole.length - 1; - - var prevHoleIdx = inHoleIdx - 1; - if ( prevHoleIdx < 0 ) prevHoleIdx = lastHoleIdx; - - var nextHoleIdx = inHoleIdx + 1; - if ( nextHoleIdx > lastHoleIdx ) nextHoleIdx = 0; - - insideAngle = isPointInsideAngle( hole[inHoleIdx], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[inShapeIdx] ); - if (! insideAngle ) { - // console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y ); - return false; - } - - return true; - } - - function intersectsShapeEdge( inShapePt, inHolePt ) { - // checks for intersections with shape edges - var sIdx, nextIdx, intersection; - for ( sIdx = 0; sIdx < shape.length; sIdx++ ) { - nextIdx = sIdx+1; nextIdx %= shape.length; - intersection = intersect_segments_2D( inShapePt, inHolePt, shape[sIdx], shape[nextIdx], true ); - if ( intersection.length > 0 ) return true; - } - - return false; - } - - var indepHoles = []; - - function intersectsHoleEdge( inShapePt, inHolePt ) { - // checks for intersections with hole edges - var ihIdx, chkHole, - hIdx, nextIdx, intersection; - for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx++ ) { - chkHole = holes[indepHoles[ihIdx]]; - for ( hIdx = 0; hIdx < chkHole.length; hIdx++ ) { - nextIdx = hIdx+1; nextIdx %= chkHole.length; - intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[hIdx], chkHole[nextIdx], true ); - if ( intersection.length > 0 ) return true; - } - } - return false; - } - - var holeIndex, shapeIndex, - shapePt, holePt, - holeIdx, cutKey, failedCuts = [], - tmpShape1, tmpShape2, - tmpHole1, tmpHole2; - - for ( var h = 0, hl = holes.length; h < hl; h ++ ) { - - indepHoles.push( h ); - - } - - var counter = indepHoles.length * 2; - while ( indepHoles.length > 0 ) { - counter --; - if ( counter < 0 ) { - console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" ); - break; - } - - // search for shape-vertex and hole-vertex, - // which can be connected without intersections - for ( shapeIndex = 0; shapeIndex < shape.length; shapeIndex++ ) { - - shapePt = shape[ shapeIndex ]; - holeIndex = -1; - - // search for hole which can be reached without intersections - for ( var h = 0; h < indepHoles.length; h ++ ) { - holeIdx = indepHoles[h]; - - // prevent multiple checks - cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx; - if ( failedCuts[cutKey] !== undefined ) continue; - - hole = holes[holeIdx]; - for ( var h2 = 0; h2 < hole.length; h2 ++ ) { - holePt = hole[ h2 ]; - if (! isCutLineInsideAngles( shapeIndex, h2 ) ) continue; - if ( intersectsShapeEdge( shapePt, holePt ) ) continue; - if ( intersectsHoleEdge( shapePt, holePt ) ) continue; - - holeIndex = h2; - indepHoles.splice(h,1); - - tmpShape1 = shape.slice( 0, shapeIndex+1 ); - tmpShape2 = shape.slice( shapeIndex ); - tmpHole1 = hole.slice( holeIndex ); - tmpHole2 = hole.slice( 0, holeIndex+1 ); - - shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); - - // Debug only, to show the selected cuts - // glob_CutLines.push( [ shapePt, holePt ] ); - - break; - } - if ( holeIndex >= 0 ) break; // hole-vertex found - - failedCuts[cutKey] = true; // remember failure - } - if ( holeIndex >= 0 ) break; // hole-vertex found - } - } - - return shape; /* shape with no holes */ - } - - - var i, il, f, face, - key, index, - allPointsMap = {}; - - // 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. - - var allpoints = contour.concat(); - - for ( var h = 0, hl = holes.length; h < hl; h ++ ) { - - Array.prototype.push.apply( allpoints, holes[h] ); - - } - - //console.log( "allpoints",allpoints, allpoints.length ); - - // prepare all points map - - for ( i = 0, il = allpoints.length; i < il; i ++ ) { - - key = allpoints[ i ].x + ":" + allpoints[ i ].y; - - if ( allPointsMap[ key ] !== undefined ) { - - console.log( "Duplicate point", key ); - - } - - allPointsMap[ key ] = i; - - } - - // remove holes by cutting paths to holes and adding them to the shape - var shapeWithoutHoles = removeHoles( contour, holes ); - - var triangles = THREE.FontUtils.Triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape - //console.log( "triangles",triangles, triangles.length ); - - // check all face vertices against all points map - - for ( i = 0, il = triangles.length; i < il; i ++ ) { - - face = triangles[ i ]; - - for ( f = 0; f < 3; f ++ ) { - - key = face[ f ].x + ":" + face[ f ].y; - - index = allPointsMap[ key ]; - - if ( index !== undefined ) { - - face[ f ] = index; - - } - - } - - } - - return triangles.concat(); - - }, - - isClockWise: function ( pts ) { - - return THREE.FontUtils.Triangulate.area( pts ) < 0; - - }, - - // Bezier Curves formulas obtained from - // http://en.wikipedia.org/wiki/B%C3%A9zier_curve - - // Quad Bezier Functions - - b2p0: function ( t, p ) { - - var k = 1 - t; - return k * k * p; - - }, - - b2p1: function ( t, p ) { - - return 2 * ( 1 - t ) * t * p; - - }, - - b2p2: function ( t, p ) { - - return t * t * p; - - }, - - b2: function ( t, p0, p1, p2 ) { - - return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 ); - - }, - - // Cubic Bezier Functions - - b3p0: function ( t, p ) { - - var k = 1 - t; - return k * k * k * p; - - }, - - b3p1: function ( t, p ) { - - var k = 1 - t; - return 3 * k * k * t * p; - - }, - - b3p2: function ( t, p ) { - - var k = 1 - t; - return 3 * k * t * t * p; - - }, - - b3p3: function ( t, p ) { - - return t * t * t * p; - - }, - - b3: function ( t, p0, p1, p2, p3 ) { - - return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 ); - - } - -}; - - -/************************************************************** - * Line - **************************************************************/ - -THREE.LineCurve = function ( v1, v2 ) { - - this.v1 = v1; - this.v2 = v2; - -}; - -THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype ); - -THREE.LineCurve.prototype.getPoint = function ( t ) { - - var point = this.v2.clone().sub(this.v1); - point.multiplyScalar( t ).add( this.v1 ); - - return point; - -}; - -// Line curve is linear, so we can overwrite default getPointAt - -THREE.LineCurve.prototype.getPointAt = function ( u ) { - - return this.getPoint( u ); - -}; - -THREE.LineCurve.prototype.getTangent = function( t ) { - - var tangent = this.v2.clone().sub(this.v1); - - return tangent.normalize(); - -}; -/************************************************************** - * Quadratic Bezier curve - **************************************************************/ - - -THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) { - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - -}; - -THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype ); - - -THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) { - - var tx, ty; - - tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); - ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); - - return new THREE.Vector2( tx, ty ); - -}; - - -THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) { - - var tx, ty; - - tx = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x ); - ty = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y ); - - // returns unit vector - - var tangent = new THREE.Vector2( tx, ty ); - tangent.normalize(); - - return tangent; - -}; -/************************************************************** - * Cubic Bezier curve - **************************************************************/ - -THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) { - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - -}; - -THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype ); - -THREE.CubicBezierCurve.prototype.getPoint = function ( t ) { - - var tx, ty; - - tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); - ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); - - return new THREE.Vector2( tx, ty ); - -}; - -THREE.CubicBezierCurve.prototype.getTangent = function( t ) { - - var tx, ty; - - tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); - ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); - - var tangent = new THREE.Vector2( tx, ty ); - tangent.normalize(); - - return tangent; - -}; -/************************************************************** - * Spline curve - **************************************************************/ - -THREE.SplineCurve = function ( points /* array of Vector2 */ ) { - - this.points = (points == undefined) ? [] : points; - -}; - -THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype ); - -THREE.SplineCurve.prototype.getPoint = function ( t ) { - - var v = new THREE.Vector2(); - var c = []; - var points = this.points, point, intPoint, weight; - point = ( points.length - 1 ) * t; - - intPoint = Math.floor( point ); - weight = point - intPoint; - - c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > points.length - 2 ? points.length -1 : intPoint + 1; - c[ 3 ] = intPoint > points.length - 3 ? points.length -1 : intPoint + 2; - - v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); - v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); - - return v; - -}; -/************************************************************** - * Ellipse curve - **************************************************************/ - -THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { - - this.aX = aX; - this.aY = aY; - - this.xRadius = xRadius; - this.yRadius = yRadius; - - this.aStartAngle = aStartAngle; - this.aEndAngle = aEndAngle; - - this.aClockwise = aClockwise; - -}; - -THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype ); - -THREE.EllipseCurve.prototype.getPoint = function ( t ) { - - var angle; - var deltaAngle = this.aEndAngle - this.aStartAngle; - - if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2; - if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2; - - if ( this.aClockwise === true ) { - - angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle ); - - } else { - - angle = this.aStartAngle + t * deltaAngle; - - } - - var tx = this.aX + this.xRadius * Math.cos( angle ); - var ty = this.aY + this.yRadius * Math.sin( angle ); - - return new THREE.Vector2( tx, ty ); - -}; - -/************************************************************** - * Arc curve - **************************************************************/ - -THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); -}; - -THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype ); -/************************************************************** - * Line3D - **************************************************************/ - -THREE.LineCurve3 = THREE.Curve.create( - - function ( v1, v2 ) { - - this.v1 = v1; - this.v2 = v2; - - }, - - function ( t ) { - - var r = new THREE.Vector3(); - - - r.subVectors( this.v2, this.v1 ); // diff - r.multiplyScalar( t ); - r.add( this.v1 ); - - return r; - - } - -); - -/************************************************************** - * Quadratic Bezier 3D curve - **************************************************************/ - -THREE.QuadraticBezierCurve3 = THREE.Curve.create( - - function ( v0, v1, v2 ) { - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - - }, - - function ( t ) { - - var tx, ty, tz; - - tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); - ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); - tz = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z ); - - return new THREE.Vector3( tx, ty, tz ); - - } - -); -/************************************************************** - * Cubic Bezier 3D curve - **************************************************************/ - -THREE.CubicBezierCurve3 = THREE.Curve.create( - - function ( v0, v1, v2, v3 ) { - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - - }, - - function ( t ) { - - var tx, ty, tz; - - tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); - ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); - tz = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z ); - - return new THREE.Vector3( tx, ty, tz ); - - } - -); -/************************************************************** - * Spline 3D curve - **************************************************************/ - - -THREE.SplineCurve3 = THREE.Curve.create( - - function ( points /* array of Vector3 */) { - - this.points = (points == undefined) ? [] : points; - - }, - - function ( t ) { - - var v = new THREE.Vector3(); - var c = []; - var points = this.points, point, intPoint, weight; - point = ( points.length - 1 ) * t; - - intPoint = Math.floor( point ); - weight = point - intPoint; - - c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; - c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; - - var pt0 = points[ c[0] ], - pt1 = points[ c[1] ], - pt2 = points[ c[2] ], - pt3 = points[ c[3] ]; - - v.x = THREE.Curve.Utils.interpolate(pt0.x, pt1.x, pt2.x, pt3.x, weight); - v.y = THREE.Curve.Utils.interpolate(pt0.y, pt1.y, pt2.y, pt3.y, weight); - v.z = THREE.Curve.Utils.interpolate(pt0.z, pt1.z, pt2.z, pt3.z, weight); - - return v; - - } - -); - - -// THREE.SplineCurve3.prototype.getTangent = function(t) { -// var v = new THREE.Vector3(); -// var c = []; -// var points = this.points, point, intPoint, weight; -// point = ( points.length - 1 ) * t; - -// intPoint = Math.floor( point ); -// weight = point - intPoint; - -// c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; -// c[ 1 ] = intPoint; -// c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; -// c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; - -// var pt0 = points[ c[0] ], -// pt1 = points[ c[1] ], -// pt2 = points[ c[2] ], -// pt3 = points[ c[3] ]; - -// // t = weight; -// v.x = THREE.Curve.Utils.tangentSpline( t, pt0.x, pt1.x, pt2.x, pt3.x ); -// v.y = THREE.Curve.Utils.tangentSpline( t, pt0.y, pt1.y, pt2.y, pt3.y ); -// v.z = THREE.Curve.Utils.tangentSpline( t, pt0.z, pt1.z, pt2.z, pt3.z ); - -// return v; - -// } -/************************************************************** - * Closed Spline 3D curve - **************************************************************/ - - -THREE.ClosedSplineCurve3 = THREE.Curve.create( - - function ( points /* array of Vector3 */) { - - this.points = (points == undefined) ? [] : points; - - }, - - function ( t ) { - - var v = new THREE.Vector3(); - var c = []; - var points = this.points, point, intPoint, weight; - point = ( points.length - 0 ) * t; - // This needs to be from 0-length +1 - - intPoint = Math.floor( point ); - weight = point - intPoint; - - intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; - c[ 0 ] = ( intPoint - 1 ) % points.length; - c[ 1 ] = ( intPoint ) % points.length; - c[ 2 ] = ( intPoint + 1 ) % points.length; - c[ 3 ] = ( intPoint + 2 ) % points.length; - - v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); - v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); - v.z = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].z, points[ c[ 1 ] ].z, points[ c[ 2 ] ].z, points[ c[ 3 ] ].z, weight ); - - return v; - - } - -); -/** - * @author mikael emtinger / http://gomo.se/ - */ - -THREE.AnimationHandler = (function() { - - var playing = []; - var library = {}; - var that = {}; - - - //--- update --- - - that.update = function( deltaTimeMS ) { - - for( var i = 0; i < playing.length; i ++ ) - playing[ i ].update( deltaTimeMS ); - - }; - - - //--- add --- - - that.addToUpdate = function( animation ) { - - if ( playing.indexOf( animation ) === -1 ) - playing.push( animation ); - - }; - - - //--- remove --- - - that.removeFromUpdate = function( animation ) { - - var index = playing.indexOf( animation ); - - if( index !== -1 ) - playing.splice( index, 1 ); - - }; - - - //--- add --- - - that.add = function( data ) { - - if ( library[ data.name ] !== undefined ) - THREE.onwarning( "THREE.AnimationHandler.add: Warning! " + data.name + " already exists in library. Overwriting." ); - - library[ data.name ] = data; - initData( data ); - - }; - - - //--- get --- - - that.get = function( name ) { - - if ( typeof name === "string" ) { - - if ( library[ name ] ) { - - return library[ name ]; - - } else { - - THREE.onwarning( "THREE.AnimationHandler.get: Couldn't find animation " + name ); - return null; - - } - - } else { - - // todo: add simple tween library - - } - - }; - - //--- parse --- - - that.parse = function( root ) { - - // setup hierarchy - - var hierarchy = []; - - if ( root instanceof THREE.SkinnedMesh ) { - - for( var b = 0; b < root.bones.length; b++ ) { - - hierarchy.push( root.bones[ b ] ); - - } - - } else { - - parseRecurseHierarchy( root, hierarchy ); - - } - - return hierarchy; - - }; - - var parseRecurseHierarchy = function( root, hierarchy ) { - - hierarchy.push( root ); - - for( var c = 0; c < root.children.length; c++ ) - parseRecurseHierarchy( root.children[ c ], hierarchy ); - - } - - - //--- init data --- - - var initData = function( data ) { - - if( data.initialized === true ) - return; - - - // loop through all keys - - for( var h = 0; h < data.hierarchy.length; h ++ ) { - - for( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - - // remove minus times - - if( data.hierarchy[ h ].keys[ k ].time < 0 ) - data.hierarchy[ h ].keys[ k ].time = 0; - - - // create quaternions - - if( data.hierarchy[ h ].keys[ k ].rot !== undefined && - !( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) { - - var quat = data.hierarchy[ h ].keys[ k ].rot; - data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion( quat[0], quat[1], quat[2], quat[3] ); - - } - - } - - - // prepare morph target keys - - if( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) { - - // get all used - - var usedMorphTargets = {}; - - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - - for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { - - var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ]; - usedMorphTargets[ morphTargetName ] = -1; - - } - - } - - data.hierarchy[ h ].usedMorphTargets = usedMorphTargets; - - - // set all used on all frames - - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - - var influences = {}; - - for ( var morphTargetName in usedMorphTargets ) { - - for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { - - if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) { - - influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ]; - break; - - } - - } - - if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) { - - influences[ morphTargetName ] = 0; - - } - - } - - data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences; - - } - - } - - - // remove all keys that are on the same time - - for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) { - - if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) { - - data.hierarchy[ h ].keys.splice( k, 1 ); - k --; - - } - - } - - - // set index - - for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { - - data.hierarchy[ h ].keys[ k ].index = k; - - } - - } - - // done - - data.initialized = true; - - }; - - - // interpolation types - - that.LINEAR = 0; - that.CATMULLROM = 1; - that.CATMULLROM_FORWARD = 2; - - return that; - -}()); - -/** - * @author mikael emtinger / http://gomo.se/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.Animation = function ( root, name ) { - - this.root = root; - this.data = THREE.AnimationHandler.get( name ); - this.hierarchy = THREE.AnimationHandler.parse( root ); - - this.currentTime = 0; - this.timeScale = 1; - - this.isPlaying = false; - this.isPaused = true; - this.loop = true; - - this.interpolationType = THREE.AnimationHandler.LINEAR; - -}; - -THREE.Animation.prototype.play = function ( startTime ) { - - this.currentTime = startTime !== undefined ? startTime : 0; - - if ( this.isPlaying === false ) { - - this.isPlaying = true; - - this.reset(); - this.update( 0 ); - - } - - this.isPaused = false; - - THREE.AnimationHandler.addToUpdate( this ); - -}; - - -THREE.Animation.prototype.pause = function() { - - if ( this.isPaused === true ) { - - THREE.AnimationHandler.addToUpdate( this ); - - } else { - - THREE.AnimationHandler.removeFromUpdate( this ); - - } - - this.isPaused = !this.isPaused; - -}; - - -THREE.Animation.prototype.stop = function() { - - this.isPlaying = false; - this.isPaused = false; - THREE.AnimationHandler.removeFromUpdate( this ); - -}; - -THREE.Animation.prototype.reset = function () { - - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - - var object = this.hierarchy[ h ]; - - object.matrixAutoUpdate = true; - - if ( object.animationCache === undefined ) { - - object.animationCache = {}; - object.animationCache.prevKey = { pos: 0, rot: 0, scl: 0 }; - object.animationCache.nextKey = { pos: 0, rot: 0, scl: 0 }; - object.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; - - } - - var prevKey = object.animationCache.prevKey; - var nextKey = object.animationCache.nextKey; - - prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ]; - prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ]; - prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ]; - - nextKey.pos = this.getNextKeyWith( "pos", h, 1 ); - nextKey.rot = this.getNextKeyWith( "rot", h, 1 ); - nextKey.scl = this.getNextKeyWith( "scl", h, 1 ); - - } - -}; - - -THREE.Animation.prototype.update = (function(){ - - var points = []; - var target = new THREE.Vector3(); - - // Catmull-Rom spline - - var interpolateCatmullRom = function ( points, scale ) { - - var c = [], v3 = [], - point, intPoint, weight, w2, w3, - pa, pb, pc, pd; - - point = ( points.length - 1 ) * scale; - intPoint = Math.floor( point ); - weight = point - intPoint; - - c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; - c[ 1 ] = intPoint; - c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1; - c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2; - - pa = points[ c[ 0 ] ]; - pb = points[ c[ 1 ] ]; - pc = points[ c[ 2 ] ]; - pd = points[ c[ 3 ] ]; - - w2 = weight * weight; - w3 = weight * w2; - - v3[ 0 ] = interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 ); - v3[ 1 ] = interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 ); - v3[ 2 ] = interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 ); - - return v3; - - }; - - var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) { - - var v0 = ( p2 - p0 ) * 0.5, - v1 = ( p3 - p1 ) * 0.5; - - return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; - - }; - - return function ( delta ) { - if ( this.isPlaying === false ) return; - - this.currentTime += delta * this.timeScale; - - // - - var vector; - var types = [ "pos", "rot", "scl" ]; - - var duration = this.data.length; - - if ( this.loop === true && this.currentTime > duration ) { - - this.currentTime %= duration; - this.reset(); - - } else if ( this.loop === false && this.currentTime > duration ) { - - this.stop(); - return; - - } - - this.currentTime = Math.min( this.currentTime, duration ); - - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - - var object = this.hierarchy[ h ]; - var animationCache = object.animationCache; - - // loop through pos/rot/scl - - for ( var t = 0; t < 3; t ++ ) { - - // get keys - - var type = types[ t ]; - var prevKey = animationCache.prevKey[ type ]; - var nextKey = animationCache.nextKey[ type ]; - - if ( nextKey.time <= this.currentTime ) { - - prevKey = this.data.hierarchy[ h ].keys[ 0 ]; - nextKey = this.getNextKeyWith( type, h, 1 ); - - while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - - prevKey = nextKey; - nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); - - } - - animationCache.prevKey[ type ] = prevKey; - animationCache.nextKey[ type ] = nextKey; - - } - - object.matrixAutoUpdate = true; - object.matrixWorldNeedsUpdate = true; - - var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time ); - - var prevXYZ = prevKey[ type ]; - var nextXYZ = nextKey[ type ]; - - if ( scale < 0 ) scale = 0; - if ( scale > 1 ) scale = 1; - - // interpolate - - if ( type === "pos" ) { - - vector = object.position; - - if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) { - - vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; - vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; - vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; - - } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - - points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ]; - points[ 1 ] = prevXYZ; - points[ 2 ] = nextXYZ; - points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ]; - - scale = scale * 0.33 + 0.33; - - var currentPoint = interpolateCatmullRom( points, scale ); - - vector.x = currentPoint[ 0 ]; - vector.y = currentPoint[ 1 ]; - vector.z = currentPoint[ 2 ]; - - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - - var forwardPoint = interpolateCatmullRom( points, scale * 1.01 ); - - target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] ); - target.sub( vector ); - target.y = 0; - target.normalize(); - - var angle = Math.atan2( target.x, target.z ); - object.rotation.set( 0, angle, 0 ); - - } - - } - - } else if ( type === "rot" ) { - - THREE.Quaternion.slerp( prevXYZ, nextXYZ, object.quaternion, scale ); - - } else if ( type === "scl" ) { - - vector = object.scale; - - vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; - vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; - vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; - - } - - } - - } - - }; - -})(); - - - - - -// Get next key with - -THREE.Animation.prototype.getNextKeyWith = function ( type, h, key ) { - - var keys = this.data.hierarchy[ h ].keys; - - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - - key = key < keys.length - 1 ? key : keys.length - 1; - - } else { - - key = key % keys.length; - - } - - for ( ; key < keys.length; key++ ) { - - if ( keys[ key ][ type ] !== undefined ) { - - return keys[ key ]; - - } - - } - - return this.data.hierarchy[ h ].keys[ 0 ]; - -}; - -// Get previous key with - -THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) { - - var keys = this.data.hierarchy[ h ].keys; - - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - - key = key > 0 ? key : 0; - - } else { - - key = key >= 0 ? key : key + keys.length; - - } - - - for ( ; key >= 0; key -- ) { - - if ( keys[ key ][ type ] !== undefined ) { - - return keys[ key ]; - - } - - } - - return this.data.hierarchy[ h ].keys[ keys.length - 1 ]; - -}; - -/** - * @author mikael emtinger / http://gomo.se/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author khang duong - * @author erik kitson - */ - -THREE.KeyFrameAnimation = function ( root, data ) { - - this.root = root; - this.data = THREE.AnimationHandler.get( data ); - this.hierarchy = THREE.AnimationHandler.parse( root ); - this.currentTime = 0; - this.timeScale = 0.001; - this.isPlaying = false; - this.isPaused = true; - this.loop = true; - - // initialize to first keyframes - - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - - var keys = this.data.hierarchy[h].keys, - sids = this.data.hierarchy[h].sids, - obj = this.hierarchy[h]; - - if ( keys.length && sids ) { - - for ( var s = 0; s < sids.length; s++ ) { - - var sid = sids[ s ], - next = this.getNextKeyWith( sid, h, 0 ); - - if ( next ) { - - next.apply( sid ); - - } - - } - - obj.matrixAutoUpdate = false; - this.data.hierarchy[h].node.updateMatrix(); - obj.matrixWorldNeedsUpdate = true; - - } - - } - -}; - -// Play - -THREE.KeyFrameAnimation.prototype.play = function ( startTime ) { - - this.currentTime = startTime !== undefined ? startTime : 0; - - if ( this.isPlaying === false ) { - - this.isPlaying = true; - - // reset key cache - - var h, hl = this.hierarchy.length, - object, - node; - - for ( h = 0; h < hl; h++ ) { - - object = this.hierarchy[ h ]; - node = this.data.hierarchy[ h ]; - - if ( node.animationCache === undefined ) { - - node.animationCache = {}; - node.animationCache.prevKey = null; - node.animationCache.nextKey = null; - node.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; - - } - - var keys = this.data.hierarchy[h].keys; - - if (keys.length) { - - node.animationCache.prevKey = keys[ 0 ]; - node.animationCache.nextKey = keys[ 1 ]; - - this.startTime = Math.min( keys[0].time, this.startTime ); - this.endTime = Math.max( keys[keys.length - 1].time, this.endTime ); - - } - - } - - this.update( 0 ); - - } - - this.isPaused = false; - - THREE.AnimationHandler.addToUpdate( this ); - -}; - - - -// Pause - -THREE.KeyFrameAnimation.prototype.pause = function() { - - if( this.isPaused ) { - - THREE.AnimationHandler.addToUpdate( this ); - - } else { - - THREE.AnimationHandler.removeFromUpdate( this ); - - } - - this.isPaused = !this.isPaused; - -}; - - -// Stop - -THREE.KeyFrameAnimation.prototype.stop = function() { - - this.isPlaying = false; - this.isPaused = false; - - THREE.AnimationHandler.removeFromUpdate( this ); - - // reset JIT matrix and remove cache - - for ( var h = 0; h < this.data.hierarchy.length; h++ ) { - - var obj = this.hierarchy[ h ]; - var node = this.data.hierarchy[ h ]; - - if ( node.animationCache !== undefined ) { - - var original = node.animationCache.originalMatrix; - - if( obj instanceof THREE.Bone ) { - - original.copy( obj.skinMatrix ); - obj.skinMatrix = original; - - } else { - - original.copy( obj.matrix ); - obj.matrix = original; - - } - - delete node.animationCache; - - } - - } - -}; - - -// Update - -THREE.KeyFrameAnimation.prototype.update = function ( delta ) { - - if ( this.isPlaying === false ) return; - - this.currentTime += delta * this.timeScale; - - // - - var duration = this.data.length; - - if ( this.loop === true && this.currentTime > duration ) { - - this.currentTime %= duration; - - } - - this.currentTime = Math.min( this.currentTime, duration ); - - for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) { - - var object = this.hierarchy[ h ]; - var node = this.data.hierarchy[ h ]; - - var keys = node.keys, - animationCache = node.animationCache; - - - if ( keys.length ) { - - var prevKey = animationCache.prevKey; - var nextKey = animationCache.nextKey; - - if ( nextKey.time <= this.currentTime ) { - - while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - - prevKey = nextKey; - nextKey = keys[ prevKey.index + 1 ]; - - } - - animationCache.prevKey = prevKey; - animationCache.nextKey = nextKey; - - } - - if ( nextKey.time >= this.currentTime ) { - - prevKey.interpolate( nextKey, this.currentTime ); - - } else { - - prevKey.interpolate( nextKey, nextKey.time ); - - } - - this.data.hierarchy[ h ].node.updateMatrix(); - object.matrixWorldNeedsUpdate = true; - - } - - } - -}; - -// Get next key with - -THREE.KeyFrameAnimation.prototype.getNextKeyWith = function( sid, h, key ) { - - var keys = this.data.hierarchy[ h ].keys; - key = key % keys.length; - - for ( ; key < keys.length; key++ ) { - - if ( keys[ key ].hasTarget( sid ) ) { - - return keys[ key ]; - - } - - } - - return keys[ 0 ]; - -}; - -// Get previous key with - -THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) { - - var keys = this.data.hierarchy[ h ].keys; - key = key >= 0 ? key : key + keys.length; - - for ( ; key >= 0; key-- ) { - - if ( keys[ key ].hasTarget( sid ) ) { - - return keys[ key ]; - - } - - } - - return keys[ keys.length - 1 ]; - -}; - -/** - * @author mrdoob / http://mrdoob.com - */ - -THREE.MorphAnimation = function ( mesh ) { - - this.mesh = mesh; - this.frames = mesh.morphTargetInfluences.length; - this.currentTime = 0; - this.duration = 1000; - this.loop = true; - - this.isPlaying = false; - -}; - -THREE.MorphAnimation.prototype = { - - play: function () { - - this.isPlaying = true; - - }, - - pause: function () { - - this.isPlaying = false; - }, - - update: ( function () { - - var lastFrame = 0; - var currentFrame = 0; - - return function ( delta ) { - - if ( this.isPlaying === false ) return; - - this.currentTime += delta; - - if ( this.loop === true && this.currentTime > this.duration ) { - - this.currentTime %= this.duration; - - } - - this.currentTime = Math.min( this.currentTime, this.duration ); - - var interpolation = this.duration / this.frames; - var frame = Math.floor( this.currentTime / interpolation ); - - if ( frame != currentFrame ) { - - this.mesh.morphTargetInfluences[ lastFrame ] = 0; - this.mesh.morphTargetInfluences[ currentFrame ] = 1; - this.mesh.morphTargetInfluences[ frame ] = 0; - - lastFrame = currentFrame; - currentFrame = frame; - - } - - this.mesh.morphTargetInfluences[ frame ] = ( this.currentTime % interpolation ) / interpolation; - this.mesh.morphTargetInfluences[ lastFrame ] = 1 - this.mesh.morphTargetInfluences[ frame ]; - - } - - } )() - -}; - -/** - * Camera for rendering cube maps - * - renders scene into axis-aligned cube - * - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.CubeCamera = function ( near, far, cubeResolution ) { - - THREE.Object3D.call( this ); - this.className = "CubeCamera"; - - var fov = 90, aspect = 1; - - var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraPX.up.set( 0, -1, 0 ); - cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) ); - this.add( cameraPX ); - - var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraNX.up.set( 0, -1, 0 ); - cameraNX.lookAt( new THREE.Vector3( -1, 0, 0 ) ); - this.add( cameraNX ); - - var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraPY.up.set( 0, 0, 1 ); - cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) ); - this.add( cameraPY ); - - var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraNY.up.set( 0, 0, -1 ); - cameraNY.lookAt( new THREE.Vector3( 0, -1, 0 ) ); - this.add( cameraNY ); - - var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraPZ.up.set( 0, -1, 0 ); - cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) ); - this.add( cameraPZ ); - - var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); - cameraNZ.up.set( 0, -1, 0 ); - cameraNZ.lookAt( new THREE.Vector3( 0, 0, -1 ) ); - this.add( cameraNZ ); - - this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } ); - - this.updateCubeMap = function ( renderer, scene ) { - - var renderTarget = this.renderTarget; - var generateMipmaps = renderTarget.generateMipmaps; - - renderTarget.generateMipmaps = false; - - renderTarget.activeCubeFace = 0; - renderer.render( scene, cameraPX, renderTarget ); - - renderTarget.activeCubeFace = 1; - renderer.render( scene, cameraNX, renderTarget ); - - renderTarget.activeCubeFace = 2; - renderer.render( scene, cameraPY, renderTarget ); - - renderTarget.activeCubeFace = 3; - renderer.render( scene, cameraNY, renderTarget ); - - renderTarget.activeCubeFace = 4; - renderer.render( scene, cameraPZ, renderTarget ); - - renderTarget.generateMipmaps = generateMipmaps; - - renderTarget.activeCubeFace = 5; - renderer.render( scene, cameraNZ, renderTarget ); - - }; - -}; - -THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); - -/** - * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog - * - * A general perpose camera, for setting FOV, Lens Focal Length, - * and switching between perspective and orthographic views easily. - * Use this only if you do not wish to manage - * both a Orthographic and Perspective Camera - * - */ - - -THREE.CombinedCamera = function ( width, height, fov, near, far, orthoNear, orthoFar ) { - - THREE.Camera.call( this ); - this.className = "CombinedCamera"; - - this.fov = fov; - - this.left = -width / 2; - this.right = width / 2 - this.top = height / 2; - this.bottom = -height / 2; - - // We could also handle the projectionMatrix internally, but just wanted to test nested camera objects - - this.cameraO = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, orthoNear, orthoFar ); - this.cameraP = new THREE.PerspectiveCamera( fov, width / height, near, far ); - - this.zoom = 1; - - this.toPerspective(); - - var aspect = width/height; - -}; - -THREE.CombinedCamera.prototype = Object.create( THREE.Camera.prototype ); - -THREE.CombinedCamera.prototype.toPerspective = function () { - - // Switches to the Perspective Camera - - this.near = this.cameraP.near; - this.far = this.cameraP.far; - - this.cameraP.fov = this.fov / this.zoom ; - - this.cameraP.updateProjectionMatrix(); - - this.projectionMatrix = this.cameraP.projectionMatrix; - - this.inPerspectiveMode = true; - this.inOrthographicMode = false; - -}; - -THREE.CombinedCamera.prototype.toOrthographic = function () { - - // Switches to the Orthographic camera estimating viewport from Perspective - - var fov = this.fov; - var aspect = this.cameraP.aspect; - var near = this.cameraP.near; - var far = this.cameraP.far; - - // The size that we set is the mid plane of the viewing frustum - - var hyperfocus = ( near + far ) / 2; - - var halfHeight = Math.tan( fov / 2 ) * hyperfocus; - var planeHeight = 2 * halfHeight; - var planeWidth = planeHeight * aspect; - var halfWidth = planeWidth / 2; - - halfHeight /= this.zoom; - halfWidth /= this.zoom; - - this.cameraO.left = -halfWidth; - this.cameraO.right = halfWidth; - this.cameraO.top = halfHeight; - this.cameraO.bottom = -halfHeight; - - // this.cameraO.left = -farHalfWidth; - // this.cameraO.right = farHalfWidth; - // this.cameraO.top = farHalfHeight; - // this.cameraO.bottom = -farHalfHeight; - - // this.cameraO.left = this.left / this.zoom; - // this.cameraO.right = this.right / this.zoom; - // this.cameraO.top = this.top / this.zoom; - // this.cameraO.bottom = this.bottom / this.zoom; - - this.cameraO.updateProjectionMatrix(); - - this.near = this.cameraO.near; - this.far = this.cameraO.far; - this.projectionMatrix = this.cameraO.projectionMatrix; - - this.inPerspectiveMode = false; - this.inOrthographicMode = true; - -}; - - -THREE.CombinedCamera.prototype.setSize = function( width, height ) { - - this.cameraP.aspect = width / height; - this.left = -width / 2; - this.right = width / 2 - this.top = height / 2; - this.bottom = -height / 2; - -}; - - -THREE.CombinedCamera.prototype.setFov = function( fov ) { - - this.fov = fov; - - if ( this.inPerspectiveMode ) { - - this.toPerspective(); - - } else { - - this.toOrthographic(); - - } - -}; - -// For mantaining similar API with PerspectiveCamera - -THREE.CombinedCamera.prototype.updateProjectionMatrix = function() { - - if ( this.inPerspectiveMode ) { - - this.toPerspective(); - - } else { - - this.toPerspective(); - this.toOrthographic(); - - } - -}; - -/* -* Uses Focal Length (in mm) to estimate and set FOV -* 35mm (fullframe) camera is used if frame size is not specified; -* Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html -*/ -THREE.CombinedCamera.prototype.setLens = function ( focalLength, frameHeight ) { - - if ( frameHeight === undefined ) frameHeight = 24; - - var fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); - - this.setFov( fov ); - - return fov; -}; - - -THREE.CombinedCamera.prototype.setZoom = function( zoom ) { - - this.zoom = zoom; - - if ( this.inPerspectiveMode ) { - - this.toPerspective(); - - } else { - - this.toOrthographic(); - - } - -}; - -THREE.CombinedCamera.prototype.toFrontView = function() { - - this.rotation.x = 0; - this.rotation.y = 0; - this.rotation.z = 0; - - // should we be modifing the matrix instead? - - this.rotationAutoUpdate = false; - -}; - -THREE.CombinedCamera.prototype.toBackView = function() { - - this.rotation.x = 0; - this.rotation.y = Math.PI; - this.rotation.z = 0; - this.rotationAutoUpdate = false; - -}; - -THREE.CombinedCamera.prototype.toLeftView = function() { - - this.rotation.x = 0; - this.rotation.y = - Math.PI / 2; - this.rotation.z = 0; - this.rotationAutoUpdate = false; - -}; - -THREE.CombinedCamera.prototype.toRightView = function() { - - this.rotation.x = 0; - this.rotation.y = Math.PI / 2; - this.rotation.z = 0; - this.rotationAutoUpdate = false; - -}; - -THREE.CombinedCamera.prototype.toTopView = function() { - - this.rotation.x = - Math.PI / 2; - this.rotation.y = 0; - this.rotation.z = 0; - this.rotationAutoUpdate = false; - -}; - -THREE.CombinedCamera.prototype.toBottomView = function() { - - this.rotation.x = Math.PI / 2; - this.rotation.y = 0; - this.rotation.z = 0; - this.rotationAutoUpdate = false; - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as - */ - -THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { - - THREE.Geometry.call( this ); - this.className = "BoxGeometry"; - - var scope = this; - - this.width = width; - this.height = height; - this.depth = depth; - - this.widthSegments = widthSegments || 1; - this.heightSegments = heightSegments || 1; - this.depthSegments = depthSegments || 1; - - var width_half = this.width / 2; - var height_half = this.height / 2; - var depth_half = this.depth / 2; - - buildPlane( 'z', 'y', - 1, - 1, this.depth, this.height, width_half, 0 ); // px - buildPlane( 'z', 'y', 1, - 1, this.depth, this.height, - width_half, 1 ); // nx - buildPlane( 'x', 'z', 1, 1, this.width, this.depth, height_half, 2 ); // py - buildPlane( 'x', 'z', 1, - 1, this.width, this.depth, - height_half, 3 ); // ny - buildPlane( 'x', 'y', 1, - 1, this.width, this.height, depth_half, 4 ); // pz - buildPlane( 'x', 'y', - 1, - 1, this.width, this.height, - depth_half, 5 ); // nz - - function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) { - - var w, ix, iy, - gridX = scope.widthSegments, - gridY = scope.heightSegments, - width_half = width / 2, - height_half = height / 2, - offset = scope.vertices.length; - - if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) { - - w = 'z'; - - } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) { - - w = 'y'; - gridY = scope.depthSegments; - - } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) { - - w = 'x'; - gridX = scope.depthSegments; - - } - - var gridX1 = gridX + 1, - gridY1 = gridY + 1, - segment_width = width / gridX, - segment_height = height / gridY, - normal = new THREE.Vector3(); - - normal[ w ] = depth > 0 ? 1 : - 1; - - for ( iy = 0; iy < gridY1; iy ++ ) { - - for ( ix = 0; ix < gridX1; ix ++ ) { - - var vector = new THREE.Vector3(); - vector[ u ] = ( ix * segment_width - width_half ) * udir; - vector[ v ] = ( iy * segment_height - height_half ) * vdir; - vector[ w ] = depth; - - scope.vertices.push( vector ); - - } - - } - - for ( iy = 0; iy < gridY; iy++ ) { - - for ( ix = 0; ix < gridX; ix++ ) { - - var a = ix + gridX1 * iy; - var b = ix + gridX1 * ( iy + 1 ); - var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); - var d = ( ix + 1 ) + gridX1 * iy; - - var uva = new THREE.Vector2( ix / gridX, 1 - iy / gridY ); - var uvb = new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY ); - var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iy + 1 ) / gridY ); - var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY ); - - var face = new THREE.Face3( a + offset, b + offset, d + offset ); - face.normal.copy( normal ); - face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); - face.materialIndex = materialIndex; - - scope.faces.push( face ); - scope.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); - - face = new THREE.Face3( b + offset, c + offset, d + offset ); - face.normal.copy( normal ); - face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); - face.materialIndex = materialIndex; - - scope.faces.push( face ); - scope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - - } - - } - - } - - this.computeCentroids(); - this.mergeVertices(); - -}; - -THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author hughes - */ - -THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { - - THREE.Geometry.call( this ); - this.className = "CircleGeometry"; - - this.radius = radius = radius || 50; - this.segments = segments = segments !== undefined ? Math.max( 3, segments ) : 8; - - this.thetaStart = thetaStart = thetaStart !== undefined ? thetaStart : 0; - this.thetaLength = thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - - var i, uvs = [], - center = new THREE.Vector3(), centerUV = new THREE.Vector2( 0.5, 0.5 ); - - this.vertices.push(center); - uvs.push( centerUV ); - - for ( i = 0; i <= segments; i ++ ) { - - var vertex = new THREE.Vector3(); - var segment = thetaStart + i / segments * thetaLength; - - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); - - this.vertices.push( vertex ); - uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, ( vertex.y / radius + 1 ) / 2 ) ); - - } - - var n = new THREE.Vector3( 0, 0, 1 ); - - for ( i = 1; i <= segments; i ++ ) { - - var v1 = i; - var v2 = i + 1 ; - var v3 = 0; - - this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uvs[ i ].clone(), uvs[ i + 1 ].clone(), centerUV.clone() ] ); - - } - - this.computeCentroids(); - this.computeFaceNormals(); - - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - -}; - -THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -// DEPRECATED - -THREE.CubeGeometry = THREE.BoxGeometry; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded ) { - - THREE.Geometry.call( this ); - this.className = "CylinderGeometry"; - - this.radiusTop = radiusTop = radiusTop !== undefined ? radiusTop : 20; - this.radiusBottom = radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; - this.height = height = height !== undefined ? height : 100; - - this.radialSegments = radialSegments = radialSegments || 8; - this.heightSegments = heightSegments = heightSegments || 1; - - this.openEnded = openEnded = openEnded !== undefined ? openEnded : false; - - var heightHalf = height / 2; - - var x, y, vertices = [], uvs = []; - - for ( y = 0; y <= heightSegments; y ++ ) { - - var verticesRow = []; - var uvsRow = []; - - var v = y / heightSegments; - var radius = v * ( radiusBottom - radiusTop ) + radiusTop; - - for ( x = 0; x <= radialSegments; x ++ ) { - - var u = x / radialSegments; - - var vertex = new THREE.Vector3(); - vertex.x = radius * Math.sin( u * Math.PI * 2 ); - vertex.y = - v * height + heightHalf; - vertex.z = radius * Math.cos( u * Math.PI * 2 ); - - this.vertices.push( vertex ); - - verticesRow.push( this.vertices.length - 1 ); - uvsRow.push( new THREE.Vector2( u, 1 - v ) ); - - } - - vertices.push( verticesRow ); - uvs.push( uvsRow ); - - } - - var tanTheta = ( radiusBottom - radiusTop ) / height; - var na, nb; - - for ( x = 0; x < radialSegments; x ++ ) { - - if ( radiusTop !== 0 ) { - - na = this.vertices[ vertices[ 0 ][ x ] ].clone(); - nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone(); - - } else { - - na = this.vertices[ vertices[ 1 ][ x ] ].clone(); - nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone(); - - } - - na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize(); - nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize(); - - for ( y = 0; y < heightSegments; y ++ ) { - - var v1 = vertices[ y ][ x ]; - var v2 = vertices[ y + 1 ][ x ]; - var v3 = vertices[ y + 1 ][ x + 1 ]; - var v4 = vertices[ y ][ x + 1 ]; - - var n1 = na.clone(); - var n2 = na.clone(); - var n3 = nb.clone(); - var n4 = nb.clone(); - - var uv1 = uvs[ y ][ x ].clone(); - var uv2 = uvs[ y + 1 ][ x ].clone(); - var uv3 = uvs[ y + 1 ][ x + 1 ].clone(); - var uv4 = uvs[ y ][ x + 1 ].clone(); - - this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); - - this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); - - } - - } - - // top cap - - if ( openEnded === false && radiusTop > 0 ) { - - this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) ); - - for ( x = 0; x < radialSegments; x ++ ) { - - var v1 = vertices[ 0 ][ x ]; - var v2 = vertices[ 0 ][ x + 1 ]; - var v3 = this.vertices.length - 1; - - var n1 = new THREE.Vector3( 0, 1, 0 ); - var n2 = new THREE.Vector3( 0, 1, 0 ); - var n3 = new THREE.Vector3( 0, 1, 0 ); - - var uv1 = uvs[ 0 ][ x ].clone(); - var uv2 = uvs[ 0 ][ x + 1 ].clone(); - var uv3 = new THREE.Vector2( uv2.x, 0 ); - - this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); - - } - - } - - // bottom cap - - if ( openEnded === false && radiusBottom > 0 ) { - - this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) ); - - for ( x = 0; x < radialSegments; x ++ ) { - - var v1 = vertices[ y ][ x + 1 ]; - var v2 = vertices[ y ][ x ]; - var v3 = this.vertices.length - 1; - - var n1 = new THREE.Vector3( 0, - 1, 0 ); - var n2 = new THREE.Vector3( 0, - 1, 0 ); - var n3 = new THREE.Vector3( 0, - 1, 0 ); - - var uv1 = uvs[ y ][ x + 1 ].clone(); - var uv2 = uvs[ y ][ x ].clone(); - var uv3 = new THREE.Vector2( uv2.x, 1 ); - - this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); - - } - - } - - this.computeCentroids(); - this.computeFaceNormals(); - -} - -THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - * Creates extruded geometry from a path shape. - * - * parameters = { - * - * curveSegments: , // number of points on the curves - * steps: , // number of points for z-side extrusions / used for subdividing segements of extrude spline too - * amount: , // Depth to extrude the shape - * - * bevelEnabled: , // turn on bevel - * bevelThickness: , // how deep into the original shape bevel goes - * bevelSize: , // how far from shape outline is bevel - * bevelSegments: , // number of bevel layers - * - * extrudePath: // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined) - * frames: // containing arrays of tangents, normals, binormals - * - * material: // material index for front and back faces - * extrudeMaterial: // material index for extrusion and beveled faces - * uvGenerator: // object that provides UV generator functions - * - * } - **/ - -THREE.ExtrudeGeometry = function ( shapes, options ) { - - if ( typeof( shapes ) === "undefined" ) { - shapes = []; - return; - } - - THREE.Geometry.call( this ); - this.className = "ExtrudeGeometry"; - - shapes = shapes instanceof Array ? shapes : [ shapes ]; - - this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); - - this.addShapeList( shapes, options ); - - this.computeCentroids(); - this.computeFaceNormals(); - - // can't really use automatic vertex normals - // as then front and back sides get smoothed too - // should do separate smoothing just for sides - - //this.computeVertexNormals(); - - //console.log( "took", ( Date.now() - startTime ) ); - -}; - -THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -THREE.ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) { - var sl = shapes.length; - - for ( var s = 0; s < sl; s ++ ) { - var shape = shapes[ s ]; - this.addShape( shape, options ); - } -}; - -THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { - - var amount = options.amount !== undefined ? options.amount : 100; - - var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10 - var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8 - var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; - - var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false - - var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; - - var steps = options.steps !== undefined ? options.steps : 1; - - var extrudePath = options.extrudePath; - var extrudePts, extrudeByPath = false; - - var material = options.material; - var extrudeMaterial = options.extrudeMaterial; - - // Use default WorldUVGenerator if no UV generators are specified. - var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator; - - var shapebb = this.shapebb; - //shapebb = shape.getBoundingBox(); - - - - var splineTube, binormal, normal, position2; - if ( extrudePath ) { - - extrudePts = extrudePath.getSpacedPoints( steps ); - - extrudeByPath = true; - bevelEnabled = false; // bevels not supported for path extrusion - - // SETUP TNB variables - - // Reuse TNB from TubeGeomtry for now. - // TODO1 - have a .isClosed in spline? - - splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false); - - // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); - - binormal = new THREE.Vector3(); - normal = new THREE.Vector3(); - position2 = new THREE.Vector3(); - - } - - // Safeguards if bevels are not enabled - - if ( ! bevelEnabled ) { - - bevelSegments = 0; - bevelThickness = 0; - bevelSize = 0; - - } - - // Variables initalization - - var ahole, h, hl; // looping of holes - var scope = this; - var bevelPoints = []; - - var shapesOffset = this.vertices.length; - - var shapePoints = shape.extractPoints( curveSegments ); - - var vertices = shapePoints.shape; - var holes = shapePoints.holes; - - var reverse = !THREE.Shape.Utils.isClockWise( vertices ) ; - - if ( reverse ) { - - vertices = vertices.reverse(); - - // Maybe we should also check if holes are in the opposite direction, just to be safe ... - - for ( h = 0, hl = holes.length; h < hl; h ++ ) { - - ahole = holes[ h ]; - - if ( THREE.Shape.Utils.isClockWise( ahole ) ) { - - holes[ h ] = ahole.reverse(); - - } - - } - - reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)! - - } - - - var faces = THREE.Shape.Utils.triangulateShape ( vertices, holes ); - - /* Vertices */ - - var contour = vertices; // vertices has all points but contour has only points of circumference - - for ( h = 0, hl = holes.length; h < hl; h ++ ) { - - ahole = holes[ h ]; - - vertices = vertices.concat( ahole ); - - } - - - function scalePt2 ( pt, vec, size ) { - - if ( !vec ) return THREE.onerror( "die, vec not specified" ); - - return vec.clone().multiplyScalar( size ).add( pt ); - - } - - var b, bs, t, z, - vert, vlen = vertices.length, - face, flen = faces.length, - cont, clen = contour.length; - - - // Find directions for point movement - - var RAD_TO_DEGREES = 180 / Math.PI; - - - function getBevelVec( inPt, inPrev, inNext ) { - - var EPSILON = 0.0000000001; - var sign = THREE.Math.sign; - - // computes for inPt the corresponding point inPt' on a new contour - // shiftet by 1 unit (length of normalized vector) to the left - // if we walk along contour clockwise, this new contour is outside the old one - // - // inPt' is the intersection of the two lines parallel to the two - // adjacent edges of inPt at a distance of 1 unit on the left side. - - var v_trans_x, v_trans_y, shrink_by = 1; // resulting translation vector for inPt - - // good reading for geometry algorithms (here: line-line intersection) - // http://geomalgorithms.com/a05-_intersect-1.html - - var v_prev_x = inPt.x - inPrev.x, v_prev_y = inPt.y - inPrev.y; - var v_next_x = inNext.x - inPt.x, v_next_y = inNext.y - inPt.y; - - var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); - - // check for colinear edges - var colinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - - if ( Math.abs( colinear0 ) > EPSILON ) { // not colinear - - // length of vectors for normalizing - - var v_prev_len = Math.sqrt( v_prev_lensq ); - var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); - - // shift adjacent points by unit vectors to the left - - var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); - var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); - - var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); - var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); - - // scaling factor for v_prev to intersection point - - var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - - ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / - ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - - // vector from inPt to intersection point - - v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); - v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); - - // Don't normalize!, otherwise sharp corners become ugly - // but prevent crazy spikes - var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ) - if ( v_trans_lensq <= 2 ) { - return new THREE.Vector2( v_trans_x, v_trans_y ); - } else { - shrink_by = Math.sqrt( v_trans_lensq / 2 ); - } - - } else { // handle special case of colinear edges - - var direction_eq = false; // assumes: opposite - if ( v_prev_x > EPSILON ) { - if ( v_next_x > EPSILON ) { direction_eq = true; } - } else { - if ( v_prev_x < -EPSILON ) { - if ( v_next_x < -EPSILON ) { direction_eq = true; } - } else { - if ( sign(v_prev_y) == sign(v_next_y) ) { direction_eq = true; } - } - } - - if ( direction_eq ) { - // console.log("Warning: lines are a straight sequence"); - v_trans_x = -v_prev_y; - v_trans_y = v_prev_x; - shrink_by = Math.sqrt( v_prev_lensq ); - } else { - // console.log("Warning: lines are a straight spike"); - v_trans_x = v_prev_x; - v_trans_y = v_prev_y; - shrink_by = Math.sqrt( v_prev_lensq / 2 ); - } - - } - - return new THREE.Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); - - } - - - var contourMovements = []; - - for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - - if ( j === il ) j = 0; - if ( k === il ) k = 0; - - // (j)---(i)---(k) - // console.log('i,j,k', i, j , k) - - var pt_i = contour[ i ]; - var pt_j = contour[ j ]; - var pt_k = contour[ k ]; - - contourMovements[ i ]= getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); - - } - - var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); - - for ( h = 0, hl = holes.length; h < hl; h ++ ) { - - ahole = holes[ h ]; - - oneHoleMovements = []; - - for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - - if ( j === il ) j = 0; - if ( k === il ) k = 0; - - // (j)---(i)---(k) - oneHoleMovements[ i ]= getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); - - } - - holesMovements.push( oneHoleMovements ); - verticesMovements = verticesMovements.concat( oneHoleMovements ); - - } - - - // Loop bevelSegments, 1 for the front, 1 for the back - - for ( b = 0; b < bevelSegments; b ++ ) { - //for ( b = bevelSegments; b > 0; b -- ) { - - t = b / bevelSegments; - z = bevelThickness * ( 1 - t ); - - //z = bevelThickness * t; - bs = bevelSize * ( Math.sin ( t * Math.PI/2 ) ) ; // curved - //bs = bevelSize * t ; // linear - - // contract shape - - for ( i = 0, il = contour.length; i < il; i ++ ) { - - vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - //vert = scalePt( contour[ i ], contourCentroid, bs, false ); - v( vert.x, vert.y, - z ); - - } - - // expand holes - - for ( h = 0, hl = holes.length; h < hl; h++ ) { - - ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; - - for ( i = 0, il = ahole.length; i < il; i++ ) { - - vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - //vert = scalePt( ahole[ i ], holesCentroids[ h ], bs, true ); - - v( vert.x, vert.y, -z ); - - } - - } - - } - - bs = bevelSize; - - // Back facing vertices - - for ( i = 0; i < vlen; i ++ ) { - - vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - - if ( !extrudeByPath ) { - - v( vert.x, vert.y, 0 ); - - } else { - - // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); - - normal.copy( splineTube.normals[0] ).multiplyScalar(vert.x); - binormal.copy( splineTube.binormals[0] ).multiplyScalar(vert.y); - - position2.copy( extrudePts[0] ).add(normal).add(binormal); - - v( position2.x, position2.y, position2.z ); - - } - - } - - // Add stepped vertices... - // Including front facing vertices - - var s; - - for ( s = 1; s <= steps; s ++ ) { - - for ( i = 0; i < vlen; i ++ ) { - - vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - - if ( !extrudeByPath ) { - - v( vert.x, vert.y, amount / steps * s ); - - } else { - - // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); - - normal.copy( splineTube.normals[s] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[s] ).multiplyScalar( vert.y ); - - position2.copy( extrudePts[s] ).add( normal ).add( binormal ); - - v( position2.x, position2.y, position2.z ); - - } - - } - - } - - - // Add bevel segments planes - - //for ( b = 1; b <= bevelSegments; b ++ ) { - for ( b = bevelSegments - 1; b >= 0; b -- ) { - - t = b / bevelSegments; - z = bevelThickness * ( 1 - t ); - //bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) ); - bs = bevelSize * Math.sin ( t * Math.PI/2 ) ; - - // contract shape - - for ( i = 0, il = contour.length; i < il; i ++ ) { - - vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - v( vert.x, vert.y, amount + z ); - - } - - // expand holes - - for ( h = 0, hl = holes.length; h < hl; h ++ ) { - - ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; - - for ( i = 0, il = ahole.length; i < il; i ++ ) { - - vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - - if ( !extrudeByPath ) { - - v( vert.x, vert.y, amount + z ); - - } else { - - v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); - - } - - } - - } - - } - - /* Faces */ - - // Top and bottom faces - - buildLidFaces(); - - // Sides faces - - buildSideFaces(); - - - ///// Internal functions - - function buildLidFaces() { - - if ( bevelEnabled ) { - - var layer = 0 ; // steps + 1 - var offset = vlen * layer; - - // Bottom faces - - for ( i = 0; i < flen; i ++ ) { - - face = faces[ i ]; - f3( face[ 2 ]+ offset, face[ 1 ]+ offset, face[ 0 ] + offset, true ); - - } - - layer = steps + bevelSegments * 2; - offset = vlen * layer; - - // Top faces - - for ( i = 0; i < flen; i ++ ) { - - face = faces[ i ]; - f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset, false ); - - } - - } else { - - // Bottom faces - - for ( i = 0; i < flen; i++ ) { - - face = faces[ i ]; - f3( face[ 2 ], face[ 1 ], face[ 0 ], true ); - - } - - // Top faces - - for ( i = 0; i < flen; i ++ ) { - - face = faces[ i ]; - f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps, false ); - - } - } - - } - - // Create faces for the z-sides of the shape - - function buildSideFaces() { - - var layeroffset = 0; - sidewalls( contour, layeroffset ); - layeroffset += contour.length; - - for ( h = 0, hl = holes.length; h < hl; h ++ ) { - - ahole = holes[ h ]; - sidewalls( ahole, layeroffset ); - - //, true - layeroffset += ahole.length; - - } - - } - - function sidewalls( contour, layeroffset ) { - - var j, k; - i = contour.length; - - while ( --i >= 0 ) { - - j = i; - k = i - 1; - if ( k < 0 ) k = contour.length - 1; - - //console.log('b', i,j, i-1, k,vertices.length); - - var s = 0, sl = steps + bevelSegments * 2; - - for ( s = 0; s < sl; s ++ ) { - - var slen1 = vlen * s; - var slen2 = vlen * ( s + 1 ); - - var a = layeroffset + j + slen1, - b = layeroffset + k + slen1, - c = layeroffset + k + slen2, - d = layeroffset + j + slen2; - - f4( a, b, c, d, contour, s, sl, j, k ); - - } - } - - } - - - function v( x, y, z ) { - - scope.vertices.push( new THREE.Vector3( x, y, z ) ); - - } - - function f3( a, b, c, isBottom ) { - - a += shapesOffset; - b += shapesOffset; - c += shapesOffset; - - // normal, color, material - scope.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); - - var uvs = isBottom ? uvgen.generateBottomUV( scope, shape, options, a, b, c ) : uvgen.generateTopUV( scope, shape, options, a, b, c ); - - scope.faceVertexUvs[ 0 ].push( uvs ); - - } - - function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { - - a += shapesOffset; - b += shapesOffset; - c += shapesOffset; - d += shapesOffset; - - scope.faces.push( new THREE.Face3( a, b, d, null, null, extrudeMaterial ) ); - scope.faces.push( new THREE.Face3( b, c, d, null, null, extrudeMaterial ) ); - - var uvs = uvgen.generateSideWallUV( scope, shape, wallContour, options, a, b, c, d, - stepIndex, stepsLength, contourIndex1, contourIndex2 ); - - scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); - scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); - - } - -}; - -THREE.ExtrudeGeometry.WorldUVGenerator = { - - generateTopUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { - var ax = geometry.vertices[ indexA ].x, - ay = geometry.vertices[ indexA ].y, - - bx = geometry.vertices[ indexB ].x, - by = geometry.vertices[ indexB ].y, - - cx = geometry.vertices[ indexC ].x, - cy = geometry.vertices[ indexC ].y; - - return [ - new THREE.Vector2( ax, ay ), - new THREE.Vector2( bx, by ), - new THREE.Vector2( cx, cy ) - ]; - - }, - - generateBottomUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { - - return this.generateTopUV( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ); - - }, - - generateSideWallUV: function( geometry, extrudedShape, wallContour, extrudeOptions, - indexA, indexB, indexC, indexD, stepIndex, stepsLength, - contourIndex1, contourIndex2 ) { - - var ax = geometry.vertices[ indexA ].x, - ay = geometry.vertices[ indexA ].y, - az = geometry.vertices[ indexA ].z, - - bx = geometry.vertices[ indexB ].x, - by = geometry.vertices[ indexB ].y, - bz = geometry.vertices[ indexB ].z, - - cx = geometry.vertices[ indexC ].x, - cy = geometry.vertices[ indexC ].y, - cz = geometry.vertices[ indexC ].z, - - dx = geometry.vertices[ indexD ].x, - dy = geometry.vertices[ indexD ].y, - dz = geometry.vertices[ indexD ].z; - - if ( Math.abs( ay - by ) < 0.01 ) { - return [ - new THREE.Vector2( ax, 1 - az ), - new THREE.Vector2( bx, 1 - bz ), - new THREE.Vector2( cx, 1 - cz ), - new THREE.Vector2( dx, 1 - dz ) - ]; - } else { - return [ - new THREE.Vector2( ay, 1 - az ), - new THREE.Vector2( by, 1 - bz ), - new THREE.Vector2( cy, 1 - cz ), - new THREE.Vector2( dy, 1 - dz ) - ]; - } - } -}; - -THREE.ExtrudeGeometry.__v1 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v2 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v3 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v4 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v5 = new THREE.Vector2(); -THREE.ExtrudeGeometry.__v6 = new THREE.Vector2(); - -/** - * @author jonobr1 / http://jonobr1.com - * - * Creates a one-sided polygonal geometry from a path shape. Similar to - * ExtrudeGeometry. - * - * parameters = { - * - * curveSegments: , // number of points on the curves. NOT USED AT THE MOMENT. - * - * material: // material index for front and back faces - * uvGenerator: // object that provides UV generator functions - * - * } - **/ - -THREE.ShapeGeometry = function ( shapes, options ) { - - THREE.Geometry.call( this ); - this.className = "ShapeGeometry"; - - if ( shapes instanceof Array === false ) shapes = [ shapes ]; - - this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); - - this.addShapeList( shapes, options ); - - this.computeCentroids(); - this.computeFaceNormals(); - -}; - -THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * Add an array of shapes to THREE.ShapeGeometry. - */ -THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) { - - for ( var i = 0, l = shapes.length; i < l; i++ ) { - - this.addShape( shapes[ i ], options ); - - } - - return this; - -}; - -/** - * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry. - */ -THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { - - if ( options === undefined ) options = {}; - var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; - - var material = options.material; - var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator; - - var shapebb = this.shapebb; - - // - - var i, l, hole, s; - - var shapesOffset = this.vertices.length; - var shapePoints = shape.extractPoints( curveSegments ); - - var vertices = shapePoints.shape; - var holes = shapePoints.holes; - - var reverse = !THREE.Shape.Utils.isClockWise( vertices ); - - if ( reverse ) { - - vertices = vertices.reverse(); - - // Maybe we should also check if holes are in the opposite direction, just to be safe... - - for ( i = 0, l = holes.length; i < l; i++ ) { - - hole = holes[ i ]; - - if ( THREE.Shape.Utils.isClockWise( hole ) ) { - - holes[ i ] = hole.reverse(); - - } - - } - - reverse = false; - - } - - var faces = THREE.Shape.Utils.triangulateShape( vertices, holes ); - - // Vertices - - var contour = vertices; - - for ( i = 0, l = holes.length; i < l; i++ ) { - - hole = holes[ i ]; - vertices = vertices.concat( hole ); - - } - - // - - var vert, vlen = vertices.length; - var face, flen = faces.length; - var cont, clen = contour.length; - - for ( i = 0; i < vlen; i++ ) { - - vert = vertices[ i ]; - - this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) ); - - } - - for ( i = 0; i < flen; i++ ) { - - face = faces[ i ]; - - var a = face[ 0 ] + shapesOffset; - var b = face[ 1 ] + shapesOffset; - var c = face[ 2 ] + shapesOffset; - - this.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); - this.faceVertexUvs[ 0 ].push( uvgen.generateBottomUV( this, shape, options, a, b, c ) ); - - } - -}; - -/** - * @author astrodud / http://astrodud.isgreat.org/ - * @author zz85 / https://github.com/zz85 - * @author bhouston / http://exocortex.com - */ - -// points - to create a closed torus, one must use a set of points -// like so: [ a, b, c, d, a ], see first is the same as last. -// segments - the number of circumference segments to create -// phiStart - the starting radian -// phiLength - the radian (0 to 2*PI) range of the lathed section -// 2*pi is a closed lathe, less than 2PI is a portion. -THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) { - - THREE.Geometry.call( this ); - this.className = "LatheGeometry"; - - segments = segments || 12; - phiStart = phiStart || 0; - phiLength = phiLength || 2 * Math.PI; - - var inversePointLength = 1.0 / ( points.length - 1 ); - var inverseSegments = 1.0 / segments; - - for ( var i = 0, il = segments; i <= il; i ++ ) { - - var phi = phiStart + i * inverseSegments * phiLength; - - var c = Math.cos( phi ), - s = Math.sin( phi ); - - for ( var j = 0, jl = points.length; j < jl; j ++ ) { - - var pt = points[ j ]; - - var vertex = new THREE.Vector3(); - - vertex.x = c * pt.x - s * pt.y; - vertex.y = s * pt.x + c * pt.y; - vertex.z = pt.z; - - this.vertices.push( vertex ); - - } - - } - - var np = points.length; - - for ( var i = 0, il = segments; i < il; i ++ ) { - - for ( var j = 0, jl = points.length - 1; j < jl; j ++ ) { - - var base = j + np * i; - var a = base; - var b = base + np; - var c = base + 1 + np; - var d = base + 1; - - var u0 = i * inverseSegments; - var v0 = j * inversePointLength; - var u1 = u0 + inverseSegments; - var v1 = v0 + inversePointLength; - - this.faces.push( new THREE.Face3( a, b, d ) ); - - this.faceVertexUvs[ 0 ].push( [ - - new THREE.Vector2( u0, v0 ), - new THREE.Vector2( u1, v0 ), - new THREE.Vector2( u0, v1 ) - - ] ); - - this.faces.push( new THREE.Face3( b, c, d ) ); - - this.faceVertexUvs[ 0 ].push( [ - - new THREE.Vector2( u1, v0 ), - new THREE.Vector2( u1, v1 ), - new THREE.Vector2( u0, v1 ) - - ] ); - - - } - - } - - this.mergeVertices(); - this.computeCentroids(); - this.computeFaceNormals(); - this.computeVertexNormals(); - -}; - -THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author mrdoob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as - */ - -THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) { - - THREE.Geometry.call( this ); - this.className = "PlaneGeometry"; - - this.width = width; - this.height = height; - - this.widthSegments = widthSegments || 1; - this.heightSegments = heightSegments || 1; - - var ix, iz; - var width_half = width / 2; - var height_half = height / 2; - - var gridX = this.widthSegments; - var gridZ = this.heightSegments; - - var gridX1 = gridX + 1; - var gridZ1 = gridZ + 1; - - var segment_width = this.width / gridX; - var segment_height = this.height / gridZ; - - var normal = new THREE.Vector3( 0, 0, 1 ); - - for ( iz = 0; iz < gridZ1; iz ++ ) { - - for ( ix = 0; ix < gridX1; ix ++ ) { - - var x = ix * segment_width - width_half; - var y = iz * segment_height - height_half; - - this.vertices.push( new THREE.Vector3( x, - y, 0 ) ); - - } - - } - - for ( iz = 0; iz < gridZ; iz ++ ) { - - for ( ix = 0; ix < gridX; ix ++ ) { - - var a = ix + gridX1 * iz; - var b = ix + gridX1 * ( iz + 1 ); - var c = ( ix + 1 ) + gridX1 * ( iz + 1 ); - var d = ( ix + 1 ) + gridX1 * iz; - - var uva = new THREE.Vector2( ix / gridX, 1 - iz / gridZ ); - var uvb = new THREE.Vector2( ix / gridX, 1 - ( iz + 1 ) / gridZ ); - var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iz + 1 ) / gridZ ); - var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iz / gridZ ); - - var face = new THREE.Face3( a, b, d ); - face.normal.copy( normal ); - face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); - - this.faces.push( face ); - this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); - - face = new THREE.Face3( b, c, d ); - face.normal.copy( normal ); - face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); - - this.faces.push( face ); - this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - - } - - } - - this.computeCentroids(); - -}; - -THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author Kaleb Murphy - */ - -THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { - - THREE.Geometry.call( this ); - this.className = "RingGeometry"; - - innerRadius = innerRadius || 0; - outerRadius = outerRadius || 50; - - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - - thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; - phiSegments = phiSegments !== undefined ? Math.max( 3, phiSegments ) : 8; - - var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); - - for ( i = 0; i <= phiSegments; i ++ ) { // concentric circles inside ring - - for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle - - var vertex = new THREE.Vector3(); - var segment = thetaStart + o / thetaSegments * thetaLength; - - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); - - this.vertices.push( vertex ); - uvs.push( new THREE.Vector2( ( vertex.x / outerRadius + 1 ) / 2, ( vertex.y / outerRadius + 1 ) / 2 ) ); - } - - radius += radiusStep; - - } - - var n = new THREE.Vector3( 0, 0, 1 ); - - for ( i = 0; i < phiSegments; i ++ ) { // concentric circles inside ring - - var thetaSegment = i * thetaSegments; - - for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle - - var segment = o + thetaSegment; - - var v1 = segment + i; - var v2 = segment + thetaSegments + i; - var v3 = segment + thetaSegments + 1 + i; - - this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); - - v1 = segment + i; - v2 = segment + thetaSegments + 1 + i; - v3 = segment + 1 + i; - - this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); - - } - } - - this.computeCentroids(); - this.computeFaceNormals(); - - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - -}; - -THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { - - THREE.Geometry.call( this ); - this.className = "SphereGeometry"; - - this.radius = radius = radius || 50; - - this.widthSegments = widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); - this.heightSegments = heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); - - this.phiStart = phiStart = phiStart !== undefined ? phiStart : 0; - this.phiLength = phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; - - this.thetaStart = thetaStart = thetaStart !== undefined ? thetaStart : 0; - this.thetaLength = thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; - - var x, y, vertices = [], uvs = []; - - for ( y = 0; y <= heightSegments; y ++ ) { - - var verticesRow = []; - var uvsRow = []; - - for ( x = 0; x <= widthSegments; x ++ ) { - - var u = x / widthSegments; - var v = y / heightSegments; - - var vertex = new THREE.Vector3(); - vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); - vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - - this.vertices.push( vertex ); - - verticesRow.push( this.vertices.length - 1 ); - uvsRow.push( new THREE.Vector2( u, 1 - v ) ); - - } - - vertices.push( verticesRow ); - uvs.push( uvsRow ); - - } - - for ( y = 0; y < this.heightSegments; y ++ ) { - - for ( x = 0; x < this.widthSegments; x ++ ) { - - var v1 = vertices[ y ][ x + 1 ]; - var v2 = vertices[ y ][ x ]; - var v3 = vertices[ y + 1 ][ x ]; - var v4 = vertices[ y + 1 ][ x + 1 ]; - - var n1 = this.vertices[ v1 ].clone().normalize(); - var n2 = this.vertices[ v2 ].clone().normalize(); - var n3 = this.vertices[ v3 ].clone().normalize(); - var n4 = this.vertices[ v4 ].clone().normalize(); - - var uv1 = uvs[ y ][ x + 1 ].clone(); - var uv2 = uvs[ y ][ x ].clone(); - var uv3 = uvs[ y + 1 ][ x ].clone(); - var uv4 = uvs[ y + 1 ][ x + 1 ].clone(); - - if ( Math.abs( this.vertices[ v1 ].y ) === this.radius ) { - - uv1.x = ( uv1.x + uv2.x ) / 2; - this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] ); - - } else if ( Math.abs( this.vertices[ v3 ].y ) === this.radius ) { - - uv3.x = ( uv3.x + uv4.x ) / 2; - this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); - - } else { - - this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); - - this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); - this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); - - } - - } - - } - - this.computeCentroids(); - this.computeFaceNormals(); - - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - -}; - -THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author alteredq / http://alteredqualia.com/ - * - * For creating 3D text geometry in three.js - * - * Text = 3D Text - * - * parameters = { - * size: , // size of the text - * height: , // thickness to extrude text - * curveSegments: , // number of points on the curves - * - * font: , // font name - * weight: , // font weight (normal, bold) - * style: , // font style (normal, italics) - * - * bevelEnabled: , // turn on bevel - * bevelThickness: , // how deep into text bevel goes - * bevelSize: , // how far from text outline is bevel - * } - * - */ - -/* Usage Examples - - // TextGeometry wrapper - - var text3d = new TextGeometry( text, options ); - - // Complete manner - - var textShapes = THREE.FontUtils.generateShapes( text, options ); - var text3d = new ExtrudeGeometry( textShapes, options ); - -*/ - - -THREE.TextGeometry = function ( text, parameters ) { - this.className = "TextGeometry"; - - parameters = parameters || {}; - - var textShapes = THREE.FontUtils.generateShapes( text, parameters ); - - // translate parameters to ExtrudeGeometry API - - parameters.amount = parameters.height !== undefined ? parameters.height : 50; - - // defaults - - if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; - if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; - if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; - - THREE.ExtrudeGeometry.call( this, textShapes, parameters ); - -}; - -THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype ); - -/** - * @author oosmoxiecode - * @author mrdoob / http://mrdoob.com/ - * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888 - */ - -THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) { - - THREE.Geometry.call( this ); - this.className = "TorusGeometry"; - - var scope = this; - - this.radius = radius || 100; - this.tube = tube || 40; - this.radialSegments = radialSegments || 8; - this.tubularSegments = tubularSegments || 6; - this.arc = arc || Math.PI * 2; - - var center = new THREE.Vector3(), uvs = [], normals = []; - - for ( var j = 0; j <= this.radialSegments; j ++ ) { - - for ( var i = 0; i <= this.tubularSegments; i ++ ) { - - var u = i / this.tubularSegments * this.arc; - var v = j / this.radialSegments * Math.PI * 2; - - center.x = this.radius * Math.cos( u ); - center.y = this.radius * Math.sin( u ); - - var vertex = new THREE.Vector3(); - vertex.x = ( this.radius + this.tube * Math.cos( v ) ) * Math.cos( u ); - vertex.y = ( this.radius + this.tube * Math.cos( v ) ) * Math.sin( u ); - vertex.z = this.tube * Math.sin( v ); - - this.vertices.push( vertex ); - - uvs.push( new THREE.Vector2( i / this.tubularSegments, j / this.radialSegments ) ); - normals.push( vertex.clone().sub( center ).normalize() ); - - } - - } - - - for ( var j = 1; j <= this.radialSegments; j ++ ) { - - for ( var i = 1; i <= this.tubularSegments; i ++ ) { - - var a = ( this.tubularSegments + 1 ) * j + i - 1; - var b = ( this.tubularSegments + 1 ) * ( j - 1 ) + i - 1; - var c = ( this.tubularSegments + 1 ) * ( j - 1 ) + i; - var d = ( this.tubularSegments + 1 ) * j + i; - - var face = new THREE.Face3( a, b, d, [ normals[ a ].clone(), normals[ b ].clone(), normals[ d ].clone() ] ); - this.faces.push( face ); - this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ d ].clone() ] ); - - face = new THREE.Face3( b, c, d, [ normals[ b ].clone(), normals[ c ].clone(), normals[ d ].clone() ] ); - this.faces.push( face ); - this.faceVertexUvs[ 0 ].push( [ uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] ); - - } - - } - - this.computeCentroids(); - this.computeFaceNormals(); - -}; - -THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author oosmoxiecode - * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473 - */ - -THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) { - - THREE.Geometry.call( this ); - this.className = "TorusKnotGeometry"; - - var scope = this; - - this.radius = radius || 100; - this.tube = tube || 40; - this.radialSegments = radialSegments || 64; - this.tubularSegments = tubularSegments || 8; - this.p = p || 2; - this.q = q || 3; - this.heightScale = heightScale || 1; - this.grid = new Array( this.radialSegments ); - - var tang = new THREE.Vector3(); - var n = new THREE.Vector3(); - var bitan = new THREE.Vector3(); - - for ( var i = 0; i < this.radialSegments; ++ i ) { - - this.grid[ i ] = new Array( this.tubularSegments ); - var u = i / this.radialSegments * 2 * this.p * Math.PI; - var p1 = getPos( u, this.q, this.p, this.radius, this.heightScale ); - var p2 = getPos( u + 0.01, this.q, this.p, this.radius, this.heightScale ); - tang.subVectors( p2, p1 ); - n.addVectors( p2, p1 ); - - bitan.crossVectors( tang, n ); - n.crossVectors( bitan, tang ); - bitan.normalize(); - n.normalize(); - - for ( var j = 0; j < this.tubularSegments; ++ j ) { - - var v = j / this.tubularSegments * 2 * Math.PI; - var cx = - this.tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. - var cy = this.tube * Math.sin( v ); - - var pos = new THREE.Vector3(); - pos.x = p1.x + cx * n.x + cy * bitan.x; - pos.y = p1.y + cx * n.y + cy * bitan.y; - pos.z = p1.z + cx * n.z + cy * bitan.z; - - this.grid[ i ][ j ] = scope.vertices.push( pos ) - 1; - - } - - } - - for ( var i = 0; i < this.radialSegments; ++ i ) { - - for ( var j = 0; j < this.tubularSegments; ++ j ) { - - var ip = ( i + 1 ) % this.radialSegments; - var jp = ( j + 1 ) % this.tubularSegments; - - var a = this.grid[ i ][ j ]; - var b = this.grid[ ip ][ j ]; - var c = this.grid[ ip ][ jp ]; - var d = this.grid[ i ][ jp ]; - - var uva = new THREE.Vector2( i / this.radialSegments, j / this.tubularSegments ); - var uvb = new THREE.Vector2( ( i + 1 ) / this.radialSegments, j / this.tubularSegments ); - var uvc = new THREE.Vector2( ( i + 1 ) / this.radialSegments, ( j + 1 ) / this.tubularSegments ); - var uvd = new THREE.Vector2( i / this.radialSegments, ( j + 1 ) / this.tubularSegments ); - - this.faces.push( new THREE.Face3( a, b, d ) ); - this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); - - this.faces.push( new THREE.Face3( b, c, d ) ); - this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - - } - } - - this.computeCentroids(); - this.computeFaceNormals(); - this.computeVertexNormals(); - - function getPos( u, in_q, in_p, radius, heightScale ) { - - var cu = Math.cos( u ); - var su = Math.sin( u ); - var quOverP = in_q / in_p * u; - var cs = Math.cos( quOverP ); - - var tx = radius * ( 2 + cs ) * 0.5 * cu; - var ty = radius * ( 2 + cs ) * su * 0.5; - var tz = heightScale * radius * Math.sin( quOverP ) * 0.5; - - return new THREE.Vector3( tx, ty, tz ); - - } - -}; - -THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author WestLangley / https://github.com/WestLangley - * @author zz85 / https://github.com/zz85 - * @author miningold / https://github.com/miningold - * - * Modified from the TorusKnotGeometry by @oosmoxiecode - * - * Creates a tube which extrudes along a 3d spline - * - * Uses parallel transport frames as described in - * http://www.cs.indiana.edu/pub/techreports/TR425.pdf - */ - -THREE.TubeGeometry = function( path, segments, radius, radialSegments, closed ) { - - THREE.Geometry.call( this ); - this.className = "TubeGeometry"; - - this.path = path; - this.segments = segments || 64; - this.radius = radius || 1; - this.radialSegments = radialSegments || 8; - this.closed = closed || false; - - this.grid = []; - - var scope = this, - - tangent, - normal, - binormal, - - numpoints = this.segments + 1, - - x, y, z, - tx, ty, tz, - u, v, - - cx, cy, - pos, pos2 = new THREE.Vector3(), - i, j, - ip, jp, - a, b, c, d, - uva, uvb, uvc, uvd; - - var frames = new THREE.TubeGeometry.FrenetFrames( this.path, this.segments, this.closed ), - tangents = frames.tangents, - normals = frames.normals, - binormals = frames.binormals; - - // proxy internals - this.tangents = tangents; - this.normals = normals; - this.binormals = binormals; - - function vert( x, y, z ) { - - return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1; - - } - - - // consruct the grid - - for ( i = 0; i < numpoints; i++ ) { - - this.grid[ i ] = []; - - u = i / ( numpoints - 1 ); - - pos = path.getPointAt( u ); - - tangent = tangents[ i ]; - normal = normals[ i ]; - binormal = binormals[ i ]; - - for ( j = 0; j < this.radialSegments; j++ ) { - - v = j / this.radialSegments * 2 * Math.PI; - - cx = -this.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. - cy = this.radius * Math.sin( v ); - - pos2.copy( pos ); - pos2.x += cx * normal.x + cy * binormal.x; - pos2.y += cx * normal.y + cy * binormal.y; - pos2.z += cx * normal.z + cy * binormal.z; - - this.grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z ); - - } - } - - - // construct the mesh - - for ( i = 0; i < this.segments; i++ ) { - - for ( j = 0; j < this.radialSegments; j++ ) { - - ip = ( this.closed ) ? (i + 1) % this.segments : i + 1; - jp = (j + 1) % this.radialSegments; - - a = this.grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! *** - b = this.grid[ ip ][ j ]; - c = this.grid[ ip ][ jp ]; - d = this.grid[ i ][ jp ]; - - uva = new THREE.Vector2( i / this.segments, j / this.radialSegments ); - uvb = new THREE.Vector2( ( i + 1 ) / this.segments, j / this.radialSegments ); - uvc = new THREE.Vector2( ( i + 1 ) / this.segments, ( j + 1 ) / this.radialSegments ); - uvd = new THREE.Vector2( i / this.segments, ( j + 1 ) / this.radialSegments ); - - this.faces.push( new THREE.Face3( a, b, d ) ); - this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); - - this.faces.push( new THREE.Face3( b, c, d ) ); - this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); - - } - } - - this.computeCentroids(); - this.computeFaceNormals(); - this.computeVertexNormals(); - -}; - -THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); - - -// For computing of Frenet frames, exposing the tangents, normals and binormals the spline -THREE.TubeGeometry.FrenetFrames = function(path, segments, closed) { - - var tangent = new THREE.Vector3(), - normal = new THREE.Vector3(), - binormal = new THREE.Vector3(), - - tangents = [], - normals = [], - binormals = [], - - vec = new THREE.Vector3(), - mat = new THREE.Matrix4(), - - numpoints = segments + 1, - theta, - epsilon = 0.0001, - smallest, - - tx, ty, tz, - i, u, v; - - - // expose internals - this.tangents = tangents; - this.normals = normals; - this.binormals = binormals; - - // compute the tangent vectors for each segment on the path - - for ( i = 0; i < numpoints; i++ ) { - - u = i / ( numpoints - 1 ); - - tangents[ i ] = path.getTangentAt( u ); - tangents[ i ].normalize(); - - } - - initialNormal3(); - - function initialNormal1(lastBinormal) { - // fixed start binormal. Has dangers of 0 vectors - normals[ 0 ] = new THREE.Vector3(); - binormals[ 0 ] = new THREE.Vector3(); - if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 ); - normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize(); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); - } - - function initialNormal2() { - - // This uses the Frenet-Serret formula for deriving binormal - var t2 = path.getTangentAt( epsilon ); - - normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize(); - binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] ); - - normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); - - } - - function initialNormal3() { - // select an initial normal vector perpenicular to the first tangent vector, - // and in the direction of the smallest tangent xyz component - - normals[ 0 ] = new THREE.Vector3(); - binormals[ 0 ] = new THREE.Vector3(); - smallest = Number.MAX_VALUE; - tx = Math.abs( tangents[ 0 ].x ); - ty = Math.abs( tangents[ 0 ].y ); - tz = Math.abs( tangents[ 0 ].z ); - - if ( tx <= smallest ) { - smallest = tx; - normal.set( 1, 0, 0 ); - } - - if ( ty <= smallest ) { - smallest = ty; - normal.set( 0, 1, 0 ); - } - - if ( tz <= smallest ) { - normal.set( 0, 0, 1 ); - } - - vec.crossVectors( tangents[ 0 ], normal ).normalize(); - - normals[ 0 ].crossVectors( tangents[ 0 ], vec ); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); - } - - - // compute the slowly-varying normal and binormal vectors for each segment on the path - - for ( i = 1; i < numpoints; i++ ) { - - normals[ i ] = normals[ i-1 ].clone(); - - binormals[ i ] = binormals[ i-1 ].clone(); - - vec.crossVectors( tangents[ i-1 ], tangents[ i ] ); - - if ( vec.length() > epsilon ) { - - vec.normalize(); - - theta = Math.acos( THREE.Math.clamp( tangents[ i-1 ].dot( tangents[ i ] ), -1, 1 ) ); // clamp for floating pt errors - - normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); - - } - - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - - } - - - // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same - - if ( closed ) { - - theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints-1 ] ), -1, 1 ) ); - theta /= ( numpoints - 1 ); - - if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints-1 ] ) ) > 0 ) { - - theta = -theta; - - } - - for ( i = 1; i < numpoints; i++ ) { - - // twist a little... - normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - - } - - } -}; - -/** - * @author clockworkgeek / https://github.com/clockworkgeek - * @author timothypratley / https://github.com/timothypratley - * @author WestLangley / http://github.com/WestLangley -*/ - -THREE.PolyhedronGeometry = function ( vertices, faces, radius, detail ) { - - THREE.Geometry.call( this ); - this.className = "PolyhedronGeometry"; - - radius = radius || 1; - detail = detail || 0; - - var that = this; - - for ( var i = 0, l = vertices.length; i < l; i ++ ) { - - prepare( new THREE.Vector3( vertices[ i ][ 0 ], vertices[ i ][ 1 ], vertices[ i ][ 2 ] ) ); - - } - - var midpoints = [], p = this.vertices; - - var f = []; - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - var v1 = p[ faces[ i ][ 0 ] ]; - var v2 = p[ faces[ i ][ 1 ] ]; - var v3 = p[ faces[ i ][ 2 ] ]; - - f[ i ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); - - } - - for ( var i = 0, l = f.length; i < l; i ++ ) { - - subdivide(f[ i ], detail); - - } - - - // Handle case when face straddles the seam - - for ( var i = 0, l = this.faceVertexUvs[ 0 ].length; i < l; i ++ ) { - - var uvs = this.faceVertexUvs[ 0 ][ i ]; - - var x0 = uvs[ 0 ].x; - var x1 = uvs[ 1 ].x; - var x2 = uvs[ 2 ].x; - - var max = Math.max( x0, Math.max( x1, x2 ) ); - var min = Math.min( x0, Math.min( x1, x2 ) ); - - if ( max > 0.9 && min < 0.1 ) { // 0.9 is somewhat arbitrary - - if ( x0 < 0.2 ) uvs[ 0 ].x += 1; - if ( x1 < 0.2 ) uvs[ 1 ].x += 1; - if ( x2 < 0.2 ) uvs[ 2 ].x += 1; - - } - - } - - - // Apply radius - - for ( var i = 0, l = this.vertices.length; i < l; i ++ ) { - - this.vertices[ i ].multiplyScalar( radius ); - - } - - - // Merge vertices - - this.mergeVertices(); - - this.computeCentroids(); - - this.computeFaceNormals(); - - this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); - - - // Project vector onto sphere's surface - - function prepare( vector ) { - - var vertex = vector.normalize().clone(); - vertex.index = that.vertices.push( vertex ) - 1; - - // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle. - - var u = azimuth( vector ) / 2 / Math.PI + 0.5; - var v = inclination( vector ) / Math.PI + 0.5; - vertex.uv = new THREE.Vector2( u, 1 - v ); - - return vertex; - - } - - - // Approximate a curved face with recursively sub-divided triangles. - - function make( v1, v2, v3 ) { - - var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); - face.centroid.add( v1 ).add( v2 ).add( v3 ).divideScalar( 3 ); - that.faces.push( face ); - - var azi = azimuth( face.centroid ); - - that.faceVertexUvs[ 0 ].push( [ - correctUV( v1.uv, v1, azi ), - correctUV( v2.uv, v2, azi ), - correctUV( v3.uv, v3, azi ) - ] ); - - } - - - // Analytically subdivide a face to the required detail level. - - function subdivide(face, detail ) { - - var cols = Math.pow(2, detail); - var cells = Math.pow(4, detail); - var a = prepare( that.vertices[ face.a ] ); - var b = prepare( that.vertices[ face.b ] ); - var c = prepare( that.vertices[ face.c ] ); - var v = []; - - // Construct all of the vertices for this subdivision. - - for ( var i = 0 ; i <= cols; i ++ ) { - - v[ i ] = []; - - var aj = prepare( a.clone().lerp( c, i / cols ) ); - var bj = prepare( b.clone().lerp( c, i / cols ) ); - var rows = cols - i; - - for ( var j = 0; j <= rows; j ++) { - - if ( j == 0 && i == cols ) { - - v[ i ][ j ] = aj; - - } else { - - v[ i ][ j ] = prepare( aj.clone().lerp( bj, j / rows ) ); - - } - - } - - } - - // Construct all of the faces. - - for ( var i = 0; i < cols ; i ++ ) { - - for ( var j = 0; j < 2 * (cols - i) - 1; j ++ ) { - - var k = Math.floor( j / 2 ); - - if ( j % 2 == 0 ) { - - make( - v[ i ][ k + 1], - v[ i + 1 ][ k ], - v[ i ][ k ] - ); - - } else { - - make( - v[ i ][ k + 1 ], - v[ i + 1][ k + 1], - v[ i + 1 ][ k ] - ); - - } - - } - - } - - } - - - // Angle around the Y axis, counter-clockwise when looking from above. - - function azimuth( vector ) { - - return Math.atan2( vector.z, -vector.x ); - - } - - - // Angle above the XZ plane. - - function inclination( vector ) { - - return Math.atan2( -vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); - - } - - - // Texture fixing helper. Spheres have some odd behaviours. - - function correctUV( uv, vector, azimuth ) { - - if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) uv = new THREE.Vector2( uv.x - 1, uv.y ); - if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.Vector2( azimuth / 2 / Math.PI + 0.5, uv.y ); - return uv.clone(); - - } - - -}; - -THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author timothypratley / https://github.com/timothypratley - */ - -THREE.IcosahedronGeometry = function ( radius, detail ) { - - this.radius = radius; - this.detail = detail; - - var t = ( 1 + Math.sqrt( 5 ) ) / 2; - - var vertices = [ - [ -1, t, 0 ], [ 1, t, 0 ], [ -1, -t, 0 ], [ 1, -t, 0 ], - [ 0, -1, t ], [ 0, 1, t ], [ 0, -1, -t ], [ 0, 1, -t ], - [ t, 0, -1 ], [ t, 0, 1 ], [ -t, 0, -1 ], [ -t, 0, 1 ] - ]; - - var faces = [ - [ 0, 11, 5 ], [ 0, 5, 1 ], [ 0, 1, 7 ], [ 0, 7, 10 ], [ 0, 10, 11 ], - [ 1, 5, 9 ], [ 5, 11, 4 ], [ 11, 10, 2 ], [ 10, 7, 6 ], [ 7, 1, 8 ], - [ 3, 9, 4 ], [ 3, 4, 2 ], [ 3, 2, 6 ], [ 3, 6, 8 ], [ 3, 8, 9 ], - [ 4, 9, 5 ], [ 2, 4, 11 ], [ 6, 2, 10 ], [ 8, 6, 7 ], [ 9, 8, 1 ] - ]; - - THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); - this.className = "IcosahedronGeometry"; - -}; - -THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author timothypratley / https://github.com/timothypratley - */ - -THREE.OctahedronGeometry = function ( radius, detail ) { - - var vertices = [ - [ 1, 0, 0 ], [ -1, 0, 0 ], [ 0, 1, 0 ], [ 0, -1, 0 ], [ 0, 0, 1 ], [ 0, 0, -1 ] - ]; - - var faces = [ - [ 0, 2, 4 ], [ 0, 4, 3 ], [ 0, 3, 5 ], [ 0, 5, 2 ], [ 1, 2, 5 ], [ 1, 5, 3 ], [ 1, 3, 4 ], [ 1, 4, 2 ] - ]; - - THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); - this.className = "OctahedronGeometry"; - -}; - -THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author timothypratley / https://github.com/timothypratley - */ - -THREE.TetrahedronGeometry = function ( radius, detail ) { - this.className = "TetrahedronGeometry"; - - var vertices = [ - [ 1, 1, 1 ], [ -1, -1, 1 ], [ -1, 1, -1 ], [ 1, -1, -1 ] - ]; - - var faces = [ - [ 2, 1, 0 ], [ 0, 3, 2 ], [ 1, 3, 0 ], [ 2, 3, 1 ] - ]; - - THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); - -}; - -THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author zz85 / https://github.com/zz85 - * Parametric Surfaces Geometry - * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 - * - * new THREE.ParametricGeometry( parametricFunction, uSegments, ySegements ); - * - */ - -THREE.ParametricGeometry = function ( func, slices, stacks ) { - - THREE.Geometry.call( this ); - this.className = "ParametricGeometry"; - - var verts = this.vertices; - var faces = this.faces; - var uvs = this.faceVertexUvs[ 0 ]; - - var i, il, j, p; - var u, v; - - var stackCount = stacks + 1; - var sliceCount = slices + 1; - - for ( i = 0; i <= stacks; i ++ ) { - - v = i / stacks; - - for ( j = 0; j <= slices; j ++ ) { - - u = j / slices; - - p = func( u, v ); - verts.push( p ); - - } - } - - var a, b, c, d; - var uva, uvb, uvc, uvd; - - for ( i = 0; i < stacks; i ++ ) { - - for ( j = 0; j < slices; j ++ ) { - - a = i * sliceCount + j; - b = i * sliceCount + j + 1; - c = (i + 1) * sliceCount + j + 1; - d = (i + 1) * sliceCount + j; - - uva = new THREE.Vector2( j / slices, i / stacks ); - uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks ); - uvc = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks ); - uvd = new THREE.Vector2( j / slices, ( i + 1 ) / stacks ); - - faces.push( new THREE.Face3( a, b, d ) ); - uvs.push( [ uva, uvb, uvd ] ); - - faces.push( new THREE.Face3( b, c, d ) ); - uvs.push( [ uvb.clone(), uvc, uvd.clone() ] ); - - } - - } - - // console.log(this); - - // magic bullet - // var diff = this.mergeVertices(); - // console.log('removed ', diff, ' vertices by merging'); - - this.computeCentroids(); - this.computeFaceNormals(); - this.computeVertexNormals(); - -}; - -THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype ); - -/** - * @author sroucheray / http://sroucheray.org/ - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.AxisHelper = function ( size ) { - - size = size || 1; - - var geometry = new THREE.Geometry(); - - geometry.vertices.push( - new THREE.Vector3(), new THREE.Vector3( size, 0, 0 ), - new THREE.Vector3(), new THREE.Vector3( 0, size, 0 ), - new THREE.Vector3(), new THREE.Vector3( 0, 0, size ) - ); - - geometry.colors.push( - new THREE.Color( 0xff0000 ), new THREE.Color( 0xffaa00 ), - new THREE.Color( 0x00ff00 ), new THREE.Color( 0xaaff00 ), - new THREE.Color( 0x0000ff ), new THREE.Color( 0x00aaff ) - ); - - var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); - - THREE.Line.call( this, geometry, material, THREE.LinePieces ); - this.className = "AxisHelper"; - -}; - -THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype ); - -/** - * @author WestLangley / http://github.com/WestLangley - * @author zz85 / http://github.com/zz85 - * @author bhouston / http://exocortex.com - * - * Creates an arrow for visualizing directions - * - * Parameters: - * dir - Vector3 - * origin - Vector3 - * length - Number - * hex - color in hex value - * headLength - Number - * headWidth - Number - */ - -THREE.ArrowHelper = function ( dir, origin, length, hex, headLength, headWidth ) { - - // dir is assumed to be normalized - - THREE.Object3D.call( this ); - this.className = "ArrowHelper"; - - if ( hex === undefined ) hex = 0xffff00; - if ( length === undefined ) length = 1; - if ( headLength === undefined ) headLength = 0.2 * length; - if ( headWidth === undefined ) headWidth = 0.2 * headLength; - - this.position = origin; - - var lineGeometry = new THREE.Geometry(); - lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ) ); - lineGeometry.vertices.push( new THREE.Vector3( 0, 1, 0 ) ); - - this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: hex } ) ); - this.line.matrixAutoUpdate = false; - this.add( this.line ); - - var coneGeometry = new THREE.CylinderGeometry( 0, 0.5, 1, 5, 1 ); - coneGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) ); - - this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: hex } ) ); - this.cone.matrixAutoUpdate = false; - this.add( this.cone ); - - this.setDirection( dir ); - this.setLength( length, headLength, headWidth ); - -}; - -THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.ArrowHelper.prototype.setDirection = function () { - - var axis = new THREE.Vector3(); - var radians; - - return function ( dir ) { - - // dir is assumed to be normalized - - if ( dir.y > 0.99999 ) { - - this.quaternion.set( 0, 0, 0, 1 ); - - } else if ( dir.y < - 0.99999 ) { - - this.quaternion.set( 1, 0, 0, 0 ); - - } else { - - axis.set( dir.z, 0, - dir.x ).normalize(); - - radians = Math.acos( dir.y ); - - this.quaternion.setFromAxisAngle( axis, radians ); - - } - - }; - -}(); - -THREE.ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { - - if ( headLength === undefined ) headLength = 0.2 * length; - if ( headWidth === undefined ) headWidth = 0.2 * headLength; - - this.line.scale.set( 1, length, 1 ); - this.line.updateMatrix(); - - this.cone.scale.set( headWidth, headLength, headWidth ); - this.cone.position.y = length; - this.cone.updateMatrix(); - -}; - -THREE.ArrowHelper.prototype.setColor = function ( hex ) { - - this.line.material.color.setHex( hex ); - this.cone.material.color.setHex( hex ); - -}; - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.BoxHelper = function ( object ) { - - // 5____4 - // 1/___0/| - // | 6__|_7 - // 2/___3/ - - var vertices = [ - new THREE.Vector3( 1, 1, 1 ), - new THREE.Vector3( - 1, 1, 1 ), - new THREE.Vector3( - 1, - 1, 1 ), - new THREE.Vector3( 1, - 1, 1 ), - - new THREE.Vector3( 1, 1, - 1 ), - new THREE.Vector3( - 1, 1, - 1 ), - new THREE.Vector3( - 1, - 1, - 1 ), - new THREE.Vector3( 1, - 1, - 1 ) - ]; - - this.vertices = vertices; - - // TODO: Wouldn't be nice if Line had .segments? - - var geometry = new THREE.Geometry(); - geometry.vertices.push( - vertices[ 0 ], vertices[ 1 ], - vertices[ 1 ], vertices[ 2 ], - vertices[ 2 ], vertices[ 3 ], - vertices[ 3 ], vertices[ 0 ], - - vertices[ 4 ], vertices[ 5 ], - vertices[ 5 ], vertices[ 6 ], - vertices[ 6 ], vertices[ 7 ], - vertices[ 7 ], vertices[ 4 ], - - vertices[ 0 ], vertices[ 4 ], - vertices[ 1 ], vertices[ 5 ], - vertices[ 2 ], vertices[ 6 ], - vertices[ 3 ], vertices[ 7 ] - ); - - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: 0xffff00 } ), THREE.LinePieces ); - - if ( object !== undefined ) { - - this.update( object ); - - } - -}; - -THREE.BoxHelper.prototype = Object.create( THREE.Line.prototype ); - -THREE.BoxHelper.prototype.update = function ( object ) { - - var geometry = object.geometry; - - if ( geometry.boundingBox === null ) { - - geometry.computeBoundingBox(); - - } - - var min = geometry.boundingBox.min; - var max = geometry.boundingBox.max; - var vertices = this.vertices; - - vertices[ 0 ].set( max.x, max.y, max.z ); - vertices[ 1 ].set( min.x, max.y, max.z ); - vertices[ 2 ].set( min.x, min.y, max.z ); - vertices[ 3 ].set( max.x, min.y, max.z ); - vertices[ 4 ].set( max.x, max.y, min.z ); - vertices[ 5 ].set( min.x, max.y, min.z ); - vertices[ 6 ].set( min.x, min.y, min.z ); - vertices[ 7 ].set( max.x, min.y, min.z ); - - this.geometry.computeBoundingSphere(); - this.geometry.verticesNeedUpdate = true; - - this.matrixAutoUpdate = false; - this.matrixWorld = object.matrixWorld; - -}; - -/** - * @author WestLangley / http://github.com/WestLangley - */ - -// a helper to show the world-axis-aligned bounding box for an object - -THREE.BoundingBoxHelper = function ( object, hex ) { - - var color = ( hex !== undefined ) ? hex : 0x888888; - - this.object = object; - - this.box = new THREE.Box3(); - - THREE.Mesh.call( this, new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: color, wireframe: true } ) ); - -}; - -THREE.BoundingBoxHelper.prototype = Object.create( THREE.Mesh.prototype ); - -THREE.BoundingBoxHelper.prototype.update = function () { - - this.box.setFromObject( this.object ); - - this.box.size( this.scale ); - - this.box.center( this.position ); - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - * - * - shows frustum, line of sight and up of the camera - * - suitable for fast updates - * - based on frustum visualization in lightgl.js shadowmap example - * http://evanw.github.com/lightgl.js/tests/shadowmap.html - */ - -THREE.CameraHelper = function ( camera ) { - - var geometry = new THREE.Geometry(); - var material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } ); - - var pointMap = {}; - - // colors - - var hexFrustum = 0xffaa00; - var hexCone = 0xff0000; - var hexUp = 0x00aaff; - var hexTarget = 0xffffff; - var hexCross = 0x333333; - - // near - - addLine( "n1", "n2", hexFrustum ); - addLine( "n2", "n4", hexFrustum ); - addLine( "n4", "n3", hexFrustum ); - addLine( "n3", "n1", hexFrustum ); - - // far - - addLine( "f1", "f2", hexFrustum ); - addLine( "f2", "f4", hexFrustum ); - addLine( "f4", "f3", hexFrustum ); - addLine( "f3", "f1", hexFrustum ); - - // sides - - addLine( "n1", "f1", hexFrustum ); - addLine( "n2", "f2", hexFrustum ); - addLine( "n3", "f3", hexFrustum ); - addLine( "n4", "f4", hexFrustum ); - - // cone - - addLine( "p", "n1", hexCone ); - addLine( "p", "n2", hexCone ); - addLine( "p", "n3", hexCone ); - addLine( "p", "n4", hexCone ); - - // up - - addLine( "u1", "u2", hexUp ); - addLine( "u2", "u3", hexUp ); - addLine( "u3", "u1", hexUp ); - - // target - - addLine( "c", "t", hexTarget ); - addLine( "p", "c", hexCross ); - - // cross - - addLine( "cn1", "cn2", hexCross ); - addLine( "cn3", "cn4", hexCross ); - - addLine( "cf1", "cf2", hexCross ); - addLine( "cf3", "cf4", hexCross ); - - function addLine( a, b, hex ) { - - addPoint( a, hex ); - addPoint( b, hex ); - - } - - function addPoint( id, hex ) { - - geometry.vertices.push( new THREE.Vector3() ); - geometry.colors.push( new THREE.Color( hex ) ); - - if ( pointMap[ id ] === undefined ) { - - pointMap[ id ] = []; - - } - - pointMap[ id ].push( geometry.vertices.length - 1 ); - - } - - THREE.Line.call( this, geometry, material, THREE.LinePieces ); - - this.camera = camera; - this.matrixWorld = camera.matrixWorld; - this.matrixAutoUpdate = false; - - this.pointMap = pointMap; - - this.update(); - -}; - -THREE.CameraHelper.prototype = Object.create( THREE.Line.prototype ); - -THREE.CameraHelper.prototype.update = function () { - - var vector = new THREE.Vector3(); - var camera = new THREE.Camera(); - var projector = new THREE.Projector(); - - return function () { - - var scope = this; - - var w = 1, h = 1; - - // we need just camera projection matrix - // world matrix must be identity - - camera.projectionMatrix.copy( this.camera.projectionMatrix ); - - // center / target - - setPoint( "c", 0, 0, -1 ); - setPoint( "t", 0, 0, 1 ); - - // near - - setPoint( "n1", -w, -h, -1 ); - setPoint( "n2", w, -h, -1 ); - setPoint( "n3", -w, h, -1 ); - setPoint( "n4", w, h, -1 ); - - // far - - setPoint( "f1", -w, -h, 1 ); - setPoint( "f2", w, -h, 1 ); - setPoint( "f3", -w, h, 1 ); - setPoint( "f4", w, h, 1 ); - - // up - - setPoint( "u1", w * 0.7, h * 1.1, -1 ); - setPoint( "u2", -w * 0.7, h * 1.1, -1 ); - setPoint( "u3", 0, h * 2, -1 ); - - // cross - - setPoint( "cf1", -w, 0, 1 ); - setPoint( "cf2", w, 0, 1 ); - setPoint( "cf3", 0, -h, 1 ); - setPoint( "cf4", 0, h, 1 ); - - setPoint( "cn1", -w, 0, -1 ); - setPoint( "cn2", w, 0, -1 ); - setPoint( "cn3", 0, -h, -1 ); - setPoint( "cn4", 0, h, -1 ); - - function setPoint( point, x, y, z ) { - - vector.set( x, y, z ); - projector.unprojectVector( vector, camera ); - - var points = scope.pointMap[ point ]; - - if ( points !== undefined ) { - - for ( var i = 0, il = points.length; i < il; i ++ ) { - - scope.geometry.vertices[ points[ i ] ].copy( vector ); - - } - - } - - } - - this.geometry.verticesNeedUpdate = true; - - }; - -}(); - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - */ - -THREE.DirectionalLightHelper = function ( light, size ) { - - THREE.Object3D.call( this ); - - this.light = light; - this.light.updateMatrixWorld(); - - this.matrixWorld = light.matrixWorld; - this.matrixAutoUpdate = false; - - size = size || 1; - var geometry = new THREE.PlaneGeometry( size, size ); - var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); - material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - - this.lightPlane = new THREE.Mesh( geometry, material ); - this.add( this.lightPlane ); - - geometry = new THREE.Geometry(); - geometry.vertices.push( new THREE.Vector3() ); - geometry.vertices.push( new THREE.Vector3() ); - - material = new THREE.LineBasicMaterial( { fog: false } ); - material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - - this.targetLine = new THREE.Line( geometry, material ); - this.add( this.targetLine ); - - this.update(); - -}; - -THREE.DirectionalLightHelper.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.DirectionalLightHelper.prototype.dispose = function () { - - this.lightPlane.geometry.dispose(); - this.lightPlane.material.dispose(); - this.targetLine.geometry.dispose(); - this.targetLine.material.dispose(); -}; - -THREE.DirectionalLightHelper.prototype.update = function () { - - var v1 = new THREE.Vector3(); - var v2 = new THREE.Vector3(); - var v3 = new THREE.Vector3(); - - return function () { - - v1.setFromMatrixPosition( this.light.matrixWorld ); - v2.setFromMatrixPosition( this.light.target.matrixWorld ); - v3.subVectors( v2, v1 ); - - this.lightPlane.lookAt( v3 ); - this.lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - - this.targetLine.geometry.vertices[ 1 ].copy( v3 ); - this.targetLine.geometry.verticesNeedUpdate = true; - this.targetLine.material.color.copy( this.lightPlane.material.color ); - - } - -}(); - - -/** - * @author WestLangley / http://github.com/WestLangley - */ - -THREE.EdgesHelper = function ( object, hex ) { - - var color = ( hex !== undefined ) ? hex : 0xffffff; - - var edge = [ 0, 0 ], hash = {}; - var sortFunction = function ( a, b ) { return a - b }; - - var keys = [ 'a', 'b', 'c' ]; - var geometry = new THREE.BufferGeometry(); - - var geometry2 = object.geometry.clone(); - - geometry2.mergeVertices(); - geometry2.computeFaceNormals(); - - var vertices = geometry2.vertices; - var faces = geometry2.faces; - var numEdges = 0; - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - for ( var j = 0; j < 3; j ++ ) { - - edge[ 0 ] = face[ keys[ j ] ]; - edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; - edge.sort( sortFunction ); - - var key = edge.toString(); - - if ( hash[ key ] === undefined ) { - - hash[ key ] = { vert1: edge[ 0 ], vert2: edge[ 1 ], face1: i, face2: undefined }; - numEdges ++; - - } else { - - hash[ key ].face2 = i; - - } - - } - - } - - geometry.addAttribute( 'position', Float32Array, 2 * numEdges, 3 ); - - var coords = geometry.attributes.position.array; - - var index = 0; - - for ( var key in hash ) { - - var h = hash[ key ]; - - if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) < 0.9999 ) { // hardwired const OK - - var vertex = vertices[ h.vert1 ]; - coords[ index ++ ] = vertex.x; - coords[ index ++ ] = vertex.y; - coords[ index ++ ] = vertex.z; - - vertex = vertices[ h.vert2 ]; - coords[ index ++ ] = vertex.x; - coords[ index ++ ] = vertex.y; - coords[ index ++ ] = vertex.z; - - } - - } - - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); - - this.matrixAutoUpdate = false; - this.matrixWorld = object.matrixWorld; - -}; - -THREE.EdgesHelper.prototype = Object.create( THREE.Line.prototype ); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ - -THREE.FaceNormalsHelper = function ( object, size, hex, linewidth ) { - - this.object = object; - - this.size = ( size !== undefined ) ? size : 1; - - var color = ( hex !== undefined ) ? hex : 0xffff00; - - var width = ( linewidth !== undefined ) ? linewidth : 1; - - var geometry = new THREE.Geometry(); - - var faces = this.object.geometry.faces; - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - geometry.vertices.push( new THREE.Vector3() ); - geometry.vertices.push( new THREE.Vector3() ); - - } - - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - - this.matrixAutoUpdate = false; - - this.normalMatrix = new THREE.Matrix3(); - - this.update(); - -}; - -THREE.FaceNormalsHelper.prototype = Object.create( THREE.Line.prototype ); - -THREE.FaceNormalsHelper.prototype.update = ( function ( object ) { - - var v1 = new THREE.Vector3(); - - return function ( object ) { - - this.object.updateMatrixWorld( true ); - - this.normalMatrix.getNormalMatrix( this.object.matrixWorld ); - - var vertices = this.geometry.vertices; - - var faces = this.object.geometry.faces; - - var worldMatrix = this.object.matrixWorld; - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - v1.copy( face.normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size ); - - var idx = 2 * i; - - vertices[ idx ].copy( face.centroid ).applyMatrix4( worldMatrix ); - - vertices[ idx + 1 ].addVectors( vertices[ idx ], v1 ); - - } - - this.geometry.verticesNeedUpdate = true; - - return this; - - } - -}()); - - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.GridHelper = function ( size, step ) { - - var geometry = new THREE.Geometry(); - var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); - - this.color1 = new THREE.Color( 0x444444 ); - this.color2 = new THREE.Color( 0x888888 ); - - for ( var i = - size; i <= size; i += step ) { - - geometry.vertices.push( - new THREE.Vector3( - size, 0, i ), new THREE.Vector3( size, 0, i ), - new THREE.Vector3( i, 0, - size ), new THREE.Vector3( i, 0, size ) - ); - - var color = i === 0 ? this.color1 : this.color2; - - geometry.colors.push( color, color, color, color ); - - } - - THREE.Line.call( this, geometry, material, THREE.LinePieces ); - -}; - -THREE.GridHelper.prototype = Object.create( THREE.Line.prototype ); - -THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) { - - this.color1.set( colorCenterLine ); - this.color2.set( colorGrid ); - - this.geometry.colorsNeedUpdate = true; - -} - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.HemisphereLightHelper = function ( light, sphereSize, arrowLength, domeSize ) { - - THREE.Object3D.call( this ); - - this.light = light; - this.light.updateMatrixWorld(); - - this.matrixWorld = light.matrixWorld; - this.matrixAutoUpdate = false; - - this.colors = [ new THREE.Color(), new THREE.Color() ]; - - var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); - geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); - - for ( var i = 0, il = 8; i < il; i ++ ) { - - geometry.faces[ i ].color = this.colors[ i < 4 ? 0 : 1 ]; - - } - - var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: true } ); - - this.lightSphere = new THREE.Mesh( geometry, material ); - this.add( this.lightSphere ); - - this.update(); - -}; - -THREE.HemisphereLightHelper.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.HemisphereLightHelper.prototype.dispose = function () { - this.lightSphere.geometry.dispose(); - this.lightSphere.material.dispose(); -}; - -THREE.HemisphereLightHelper.prototype.update = function () { - - var vector = new THREE.Vector3(); - - return function () { - - this.colors[ 0 ].copy( this.light.color ).multiplyScalar( this.light.intensity ); - this.colors[ 1 ].copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); - - this.lightSphere.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); - this.lightSphere.geometry.colorsNeedUpdate = true; - - } - -}(); - - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.PointLightHelper = function ( light, sphereSize ) { - - this.light = light; - this.light.updateMatrixWorld(); - - var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); - var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); - material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - - THREE.Mesh.call( this, geometry, material ); - - this.matrixWorld = this.light.matrixWorld; - this.matrixAutoUpdate = false; - - /* - var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); - var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); - - this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); - this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); - - var d = light.distance; - - if ( d === 0.0 ) { - - this.lightDistance.visible = false; - - } else { - - this.lightDistance.scale.set( d, d, d ); - - } - - this.add( this.lightDistance ); - */ - -}; - -THREE.PointLightHelper.prototype = Object.create( THREE.Mesh.prototype ); - -THREE.PointLightHelper.prototype.dispose = function () { - - this.geometry.dispose(); - this.material.dispose(); -}; - -THREE.PointLightHelper.prototype.update = function () { - - this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - - /* - var d = this.light.distance; - - if ( d === 0.0 ) { - - this.lightDistance.visible = false; - - } else { - - this.lightDistance.visible = true; - this.lightDistance.scale.set( d, d, d ); - - } - */ - -}; - - -/** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ - -THREE.SpotLightHelper = function ( light ) { - - THREE.Object3D.call( this ); - - this.light = light; - this.light.updateMatrixWorld(); - - this.matrixWorld = light.matrixWorld; - this.matrixAutoUpdate = false; - - var geometry = new THREE.CylinderGeometry( 0, 1, 1, 8, 1, true ); - - geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, -0.5, 0 ) ); - geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); - - var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); - - this.cone = new THREE.Mesh( geometry, material ); - this.add( this.cone ); - - this.update(); - -}; - -THREE.SpotLightHelper.prototype = Object.create( THREE.Object3D.prototype ); - -THREE.SpotLightHelper.prototype.dispose = function () { - this.cone.geometry.dispose(); - this.cone.material.dispose(); -}; - -THREE.SpotLightHelper.prototype.update = function () { - - var vector = new THREE.Vector3(); - var vector2 = new THREE.Vector3(); - - return function () { - - var coneLength = this.light.distance ? this.light.distance : 10000; - var coneWidth = coneLength * Math.tan( this.light.angle ); - - this.cone.scale.set( coneWidth, coneWidth, coneLength ); - - vector.setFromMatrixPosition( this.light.matrixWorld ); - vector2.setFromMatrixPosition( this.light.target.matrixWorld ); - - this.cone.lookAt( vector2.sub( vector ) ); - - this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); - - }; - -}(); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ - -THREE.VertexNormalsHelper = function ( object, size, hex, linewidth ) { - - this.object = object; - - this.size = ( size !== undefined ) ? size : 1; - - var color = ( hex !== undefined ) ? hex : 0xff0000; - - var width = ( linewidth !== undefined ) ? linewidth : 1; - - var geometry = new THREE.Geometry(); - - var vertices = object.geometry.vertices; - - var faces = object.geometry.faces; - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - - geometry.vertices.push( new THREE.Vector3() ); - geometry.vertices.push( new THREE.Vector3() ); - - } - - } - - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - - this.matrixAutoUpdate = false; - - this.normalMatrix = new THREE.Matrix3(); - - this.update(); - -}; - -THREE.VertexNormalsHelper.prototype = Object.create( THREE.Line.prototype ); - -THREE.VertexNormalsHelper.prototype.update = ( function ( object ) { - - var v1 = new THREE.Vector3(); - - return function( object ) { - - var keys = [ 'a', 'b', 'c', 'd' ]; - - this.object.updateMatrixWorld( true ); - - this.normalMatrix.getNormalMatrix( this.object.matrixWorld ); - - var vertices = this.geometry.vertices; - - var verts = this.object.geometry.vertices; - - var faces = this.object.geometry.faces; - - var worldMatrix = this.object.matrixWorld; - - var idx = 0; - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - - var vertexId = face[ keys[ j ] ]; - var vertex = verts[ vertexId ]; - - var normal = face.vertexNormals[ j ]; - - vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); - - v1.copy( normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size ); - - v1.add( vertices[ idx ] ); - idx = idx + 1; - - vertices[ idx ].copy( v1 ); - idx = idx + 1; - - } - - } - - this.geometry.verticesNeedUpdate = true; - - return this; - - } - -}()); - -/** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley -*/ - -THREE.VertexTangentsHelper = function ( object, size, hex, linewidth ) { - - this.object = object; - - this.size = ( size !== undefined ) ? size : 1; - - var color = ( hex !== undefined ) ? hex : 0x0000ff; - - var width = ( linewidth !== undefined ) ? linewidth : 1; - - var geometry = new THREE.Geometry(); - - var vertices = object.geometry.vertices; - - var faces = object.geometry.faces; - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { - - geometry.vertices.push( new THREE.Vector3() ); - geometry.vertices.push( new THREE.Vector3() ); - - } - - } - - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); - - this.matrixAutoUpdate = false; - - this.update(); - -}; - -THREE.VertexTangentsHelper.prototype = Object.create( THREE.Line.prototype ); - -THREE.VertexTangentsHelper.prototype.update = ( function ( object ) { - - var v1 = new THREE.Vector3(); - - return function( object ) { - - var keys = [ 'a', 'b', 'c', 'd' ]; - - this.object.updateMatrixWorld( true ); - - var vertices = this.geometry.vertices; - - var verts = this.object.geometry.vertices; - - var faces = this.object.geometry.faces; - - var worldMatrix = this.object.matrixWorld; - - var idx = 0; - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { - - var vertexId = face[ keys[ j ] ]; - var vertex = verts[ vertexId ]; - - var tangent = face.vertexTangents[ j ]; - - vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); - - v1.copy( tangent ).transformDirection( worldMatrix ).multiplyScalar( this.size ); - - v1.add( vertices[ idx ] ); - idx = idx + 1; - - vertices[ idx ].copy( v1 ); - idx = idx + 1; - - } - - } - - this.geometry.verticesNeedUpdate = true; - - return this; - - } - -}()); - -/** - * @author mrdoob / http://mrdoob.com/ - */ - -THREE.WireframeHelper = function ( object, hex ) { - - var color = ( hex !== undefined ) ? hex : 0xffffff; - - var edge = [ 0, 0 ], hash = {}; - var sortFunction = function ( a, b ) { return a - b }; - - var keys = [ 'a', 'b', 'c' ]; - var geometry = new THREE.BufferGeometry(); - - if ( object.geometry instanceof THREE.Geometry ) { - - var vertices = object.geometry.vertices; - var faces = object.geometry.faces; - var numEdges = 0; - - // allocate maximal size - var edges = new Uint32Array( 6 * faces.length ); - - for ( var i = 0, l = faces.length; i < l; i ++ ) { - - var face = faces[ i ]; - - for ( var j = 0; j < 3; j ++ ) { - - edge[ 0 ] = face[ keys[ j ] ]; - edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; - edge.sort( sortFunction ); - - var key = edge.toString(); - - if ( hash[ key ] === undefined ) { - - edges[ 2 * numEdges ] = edge[ 0 ]; - edges[ 2 * numEdges + 1 ] = edge[ 1 ]; - hash[ key ] = true; - numEdges ++; - - } - - } - - } - - geometry.addAttribute( 'position', Float32Array, 2 * numEdges, 3 ); - - var coords = geometry.attributes.position.array; - - for ( var i = 0, l = numEdges; i < l; i ++ ) { - - for ( var j = 0; j < 2; j ++ ) { - - var vertex = vertices[ edges [ 2 * i + j] ]; - - var index = 6 * i + 3 * j; - coords[ index + 0 ] = vertex.x; - coords[ index + 1 ] = vertex.y; - coords[ index + 2 ] = vertex.z; - - } - - } - - } else if ( object.geometry instanceof THREE.BufferGeometry && object.geometry.attributes.index !== undefined ) { // indexed BufferGeometry - - var vertices = object.geometry.attributes.position.array; - var indices = object.geometry.attributes.index.array; - var offsets = object.geometry.offsets; - var numEdges = 0; - - // allocate maximal size - var edges = new Uint32Array( 2 * indices.length ); - - for ( var o = 0, ol = offsets.length; o < ol; ++ o ) { - - var start = offsets[ o ].start; - var count = offsets[ o ].count; - var index = offsets[ o ].index; - - for ( var i = start, il = start + count; i < il; i += 3 ) { - - for ( var j = 0; j < 3; j ++ ) { - - edge[ 0 ] = index + indices[ i + j ]; - edge[ 1 ] = index + indices[ i + ( j + 1 ) % 3 ]; - edge.sort( sortFunction ); - - var key = edge.toString(); - - if ( hash[ key ] === undefined ) { - - edges[ 2 * numEdges ] = edge[ 0 ]; - edges[ 2 * numEdges + 1 ] = edge[ 1 ]; - hash[ key ] = true; - numEdges ++; - - } - - } - - } - - } - - geometry.addAttribute( 'position', Float32Array, 2 * numEdges, 3 ); - - var coords = geometry.attributes.position.array; - - for ( var i = 0, l = numEdges; i < l; i ++ ) { - - for ( var j = 0; j < 2; j ++ ) { - - var index = 6 * i + 3 * j; - var index2 = 3 * edges[ 2 * i + j]; - coords[ index + 0 ] = vertices[ index2 ]; - coords[ index + 1 ] = vertices[ index2 + 1 ]; - coords[ index + 2 ] = vertices[ index2 + 2 ]; - - } - - } - - } else if ( object.geometry instanceof THREE.BufferGeometry ) { // non-indexed BufferGeometry - - var vertices = object.geometry.attributes.position.array; - var numEdges = vertices.length / 3; - var numTris = numEdges / 3; - - geometry.addAttribute( 'position', Float32Array, 2 * numEdges, 3 ); - - var coords = geometry.attributes.position.array; - - for ( var i = 0, l = numTris; i < l; i ++ ) { - - for ( var j = 0; j < 3; j ++ ) { - - var index = 18 * i + 6 * j; - - var index1 = 9 * i + 3 * j; - coords[ index + 0 ] = vertices[ index1 ]; - coords[ index + 1 ] = vertices[ index1 + 1 ]; - coords[ index + 2 ] = vertices[ index1 + 2 ]; - - var index2 = 9 * i + 3 * ( ( j + 1 ) % 3 ); - coords[ index + 3 ] = vertices[ index2 ]; - coords[ index + 4 ] = vertices[ index2 + 1 ]; - coords[ index + 5 ] = vertices[ index2 + 2 ]; - - } - - } - - } - - THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); - - this.matrixAutoUpdate = false; - this.matrixWorld = object.matrixWorld; - -}; - -THREE.WireframeHelper.prototype = Object.create( THREE.Line.prototype ); - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.ImmediateRenderObject = function () { - - THREE.Object3D.call( this ); - - this.render = function ( renderCallback ) { }; - -}; - -THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype ); - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.LensFlare = function ( texture, size, distance, blending, color ) { - - THREE.Object3D.call( this ); - - this.lensFlares = []; - - this.positionScreen = new THREE.Vector3(); - this.customUpdateCallback = undefined; - - if( texture !== undefined ) { - - this.add( texture, size, distance, blending, color ); - - } - -}; - -THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype ); - - -/* - * Add: adds another flare - */ - -THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) { - - if( size === undefined ) size = -1; - if( distance === undefined ) distance = 0; - if( opacity === undefined ) opacity = 1; - if( color === undefined ) color = new THREE.Color( 0xffffff ); - if( blending === undefined ) blending = THREE.NormalBlending; - - distance = Math.min( distance, Math.max( 0, distance ) ); - - this.lensFlares.push( { texture: texture, // THREE.Texture - size: size, // size in pixels (-1 = use texture.width) - distance: distance, // distance (0-1) from light source (0=at light source) - x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is ontop z = 1 is back - scale: 1, // scale - rotation: 1, // rotation - opacity: opacity, // opacity - color: color, // color - blending: blending } ); // blending - -}; - - -/* - * Update lens flares update positions on all flares based on the screen position - * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way. - */ - -THREE.LensFlare.prototype.updateLensFlares = function () { - - var f, fl = this.lensFlares.length; - var flare; - var vecX = -this.positionScreen.x * 2; - var vecY = -this.positionScreen.y * 2; - - for( f = 0; f < fl; f ++ ) { - - flare = this.lensFlares[ f ]; - - flare.x = this.positionScreen.x + vecX * flare.distance; - flare.y = this.positionScreen.y + vecY * flare.distance; - - flare.wantedRotation = flare.x * Math.PI * 0.25; - flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; - - } - -}; - - - - - - - - - - - - - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.MorphBlendMesh = function( geometry, material ) { - - THREE.Mesh.call( this, geometry, material ); - - this.animationsMap = {}; - this.animationsList = []; - - // prepare default animation - // (all frames played together in 1 second) - - var numFrames = this.geometry.morphTargets.length; - - var name = "__default"; - - var startFrame = 0; - var endFrame = numFrames - 1; - - var fps = numFrames / 1; - - this.createAnimation( name, startFrame, endFrame, fps ); - this.setAnimationWeight( name, 1 ); - -}; - -THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype ); - -THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { - - var animation = { - - startFrame: start, - endFrame: end, - - length: end - start + 1, - - fps: fps, - duration: ( end - start ) / fps, - - lastFrame: 0, - currentFrame: 0, - - active: false, - - time: 0, - direction: 1, - weight: 1, - - directionBackwards: false, - mirroredLoop: false - - }; - - this.animationsMap[ name ] = animation; - this.animationsList.push( animation ); - -}; - -THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { - - var pattern = /([a-z]+)(\d+)/; - - var firstAnimation, frameRanges = {}; - - var geometry = this.geometry; - - for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { - - var morph = geometry.morphTargets[ i ]; - var chunks = morph.name.match( pattern ); - - if ( chunks && chunks.length > 1 ) { - - var name = chunks[ 1 ]; - var num = chunks[ 2 ]; - - if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: -Infinity }; - - var range = frameRanges[ name ]; - - if ( i < range.start ) range.start = i; - if ( i > range.end ) range.end = i; - - if ( ! firstAnimation ) firstAnimation = name; - - } - - } - - for ( var name in frameRanges ) { - - var range = frameRanges[ name ]; - this.createAnimation( name, range.start, range.end, fps ); - - } - - this.firstAnimation = firstAnimation; - -}; - -THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.direction = 1; - animation.directionBackwards = false; - - } - -}; - -THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.direction = -1; - animation.directionBackwards = true; - - } - -}; - -THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.fps = fps; - animation.duration = ( animation.end - animation.start ) / animation.fps; - - } - -}; - -THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.duration = duration; - animation.fps = ( animation.end - animation.start ) / animation.duration; - - } - -}; - -THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.weight = weight; - - } - -}; - -THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.time = time; - - } - -}; - -THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) { - - var time = 0; - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - time = animation.time; - - } - - return time; - -}; - -THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { - - var duration = -1; - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - duration = animation.duration; - - } - - return duration; - -}; - -THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.time = 0; - animation.active = true; - - } else { - - THREE.onwarning( "animation[" + name + "] undefined" ); - - } - -}; - -THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) { - - var animation = this.animationsMap[ name ]; - - if ( animation ) { - - animation.active = false; - - } - -}; - -THREE.MorphBlendMesh.prototype.update = function ( delta ) { - - for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) { - - var animation = this.animationsList[ i ]; - - if ( ! animation.active ) continue; - - var frameTime = animation.duration / animation.length; - - animation.time += animation.direction * delta; - - if ( animation.mirroredLoop ) { - - if ( animation.time > animation.duration || animation.time < 0 ) { - - animation.direction *= -1; - - if ( animation.time > animation.duration ) { - - animation.time = animation.duration; - animation.directionBackwards = true; - - } - - if ( animation.time < 0 ) { - - animation.time = 0; - animation.directionBackwards = false; - - } - - } - - } else { - - animation.time = animation.time % animation.duration; - - if ( animation.time < 0 ) animation.time += animation.duration; - - } - - var keyframe = animation.startFrame + THREE.Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 ); - var weight = animation.weight; - - if ( keyframe !== animation.currentFrame ) { - - this.morphTargetInfluences[ animation.lastFrame ] = 0; - this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight; - - this.morphTargetInfluences[ keyframe ] = 0; - - animation.lastFrame = animation.currentFrame; - animation.currentFrame = keyframe; - - } - - var mix = ( animation.time % frameTime ) / frameTime; - - if ( animation.directionBackwards ) mix = 1 - mix; - - this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; - this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; - - } - -}; - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.LensFlarePlugin = function () { - - var _gl, _renderer, _precision, _lensFlare = {}; - - this.init = function ( renderer ) { - - _gl = renderer.context; - _renderer = renderer; - - _precision = renderer.getPrecision(); - - _lensFlare.vertices = new Float32Array( 8 + 8 ); - _lensFlare.faces = new Uint16Array( 6 ); - - var i = 0; - _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = -1; // vertex - _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 0; // uv... etc. - - _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = -1; - _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 0; - - _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; - _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; - - _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = 1; - _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 1; - - i = 0; - _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 1; _lensFlare.faces[ i++ ] = 2; - _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 2; _lensFlare.faces[ i++ ] = 3; - - // buffers - - _lensFlare.vertexBuffer = _gl.createBuffer(); - _lensFlare.elementBuffer = _gl.createBuffer(); - - _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, _lensFlare.vertices, _gl.STATIC_DRAW ); - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.faces, _gl.STATIC_DRAW ); - - // textures - - _lensFlare.tempTexture = _gl.createTexture(); - _lensFlare.occlusionTexture = _gl.createTexture(); - - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); - _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, 16, 16, 0, _gl.RGB, _gl.UNSIGNED_BYTE, null ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST ); - - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture ); - _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, 16, 16, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, null ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST ); - _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST ); - - if ( _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) <= 0 ) { - - _lensFlare.hasVertexTexture = false; - _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlare" ], _precision ); - - } else { - - _lensFlare.hasVertexTexture = true; - _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlareVertexTexture" ], _precision ); - - } - - _lensFlare.attributes = {}; - _lensFlare.uniforms = {}; - - _lensFlare.attributes.vertex = _gl.getAttribLocation ( _lensFlare.program, "position" ); - _lensFlare.attributes.uv = _gl.getAttribLocation ( _lensFlare.program, "uv" ); - - _lensFlare.uniforms.renderType = _gl.getUniformLocation( _lensFlare.program, "renderType" ); - _lensFlare.uniforms.map = _gl.getUniformLocation( _lensFlare.program, "map" ); - _lensFlare.uniforms.occlusionMap = _gl.getUniformLocation( _lensFlare.program, "occlusionMap" ); - _lensFlare.uniforms.opacity = _gl.getUniformLocation( _lensFlare.program, "opacity" ); - _lensFlare.uniforms.color = _gl.getUniformLocation( _lensFlare.program, "color" ); - _lensFlare.uniforms.scale = _gl.getUniformLocation( _lensFlare.program, "scale" ); - _lensFlare.uniforms.rotation = _gl.getUniformLocation( _lensFlare.program, "rotation" ); - _lensFlare.uniforms.screenPosition = _gl.getUniformLocation( _lensFlare.program, "screenPosition" ); - - }; - - - /* - * Render lens flares - * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, - * reads these back and calculates occlusion. - * Then _lensFlare.update_lensFlares() is called to re-position and - * update transparency of flares. Then they are rendered. - * - */ - - this.render = function ( scene, camera, viewportWidth, viewportHeight ) { - - var flares = scene.__webglFlares, - nFlares = flares.length; - - if ( ! nFlares ) return; - - var tempPosition = new THREE.Vector3(); - - var invAspect = viewportHeight / viewportWidth, - halfViewportWidth = viewportWidth * 0.5, - halfViewportHeight = viewportHeight * 0.5; - - var size = 16 / viewportHeight, - scale = new THREE.Vector2( size * invAspect, size ); - - var screenPosition = new THREE.Vector3( 1, 1, 0 ), - screenPositionPixels = new THREE.Vector2( 1, 1 ); - - var uniforms = _lensFlare.uniforms, - attributes = _lensFlare.attributes; - - // set _lensFlare program and reset blending - - _gl.useProgram( _lensFlare.program ); - - _gl.enableVertexAttribArray( _lensFlare.attributes.vertex ); - _gl.enableVertexAttribArray( _lensFlare.attributes.uv ); - - // loop through all lens flares to update their occlusion and positions - // setup gl and common used attribs/unforms - - _gl.uniform1i( uniforms.occlusionMap, 0 ); - _gl.uniform1i( uniforms.map, 1 ); - - _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer ); - _gl.vertexAttribPointer( attributes.vertex, 2, _gl.FLOAT, false, 2 * 8, 0 ); - _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 ); - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer ); - - _gl.disable( _gl.CULL_FACE ); - _gl.depthMask( false ); - - var i, j, jl, flare, sprite; - - for ( i = 0; i < nFlares; i ++ ) { - - size = 16 / viewportHeight; - scale.set( size * invAspect, size ); - - // calc object screen position - - flare = flares[ i ]; - - tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] ); - - tempPosition.applyMatrix4( camera.matrixWorldInverse ); - tempPosition.applyProjection( camera.projectionMatrix ); - - // setup arrays for gl programs - - screenPosition.copy( tempPosition ) - - screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth; - screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight; - - // screen cull - - if ( _lensFlare.hasVertexTexture || ( - screenPositionPixels.x > 0 && - screenPositionPixels.x < viewportWidth && - screenPositionPixels.y > 0 && - screenPositionPixels.y < viewportHeight ) ) { - - // save current RGB to temp texture - - _gl.activeTexture( _gl.TEXTURE1 ); - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); - _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); - - - // render pink quad - - _gl.uniform1i( uniforms.renderType, 0 ); - _gl.uniform2f( uniforms.scale, scale.x, scale.y ); - _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); - - _gl.disable( _gl.BLEND ); - _gl.enable( _gl.DEPTH_TEST ); - - _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); - - - // copy result to occlusionMap - - _gl.activeTexture( _gl.TEXTURE0 ); - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture ); - _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); - - - // restore graphics - - _gl.uniform1i( uniforms.renderType, 1 ); - _gl.disable( _gl.DEPTH_TEST ); - - _gl.activeTexture( _gl.TEXTURE1 ); - _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); - _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); - - - // update object positions - - flare.positionScreen.copy( screenPosition ) - - if ( flare.customUpdateCallback ) { - - flare.customUpdateCallback( flare ); - - } else { - - flare.updateLensFlares(); - - } - - // render flares - - _gl.uniform1i( uniforms.renderType, 2 ); - _gl.enable( _gl.BLEND ); - - for ( j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { - - sprite = flare.lensFlares[ j ]; - - if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { - - screenPosition.x = sprite.x; - screenPosition.y = sprite.y; - screenPosition.z = sprite.z; - - size = sprite.size * sprite.scale / viewportHeight; - - scale.x = size * invAspect; - scale.y = size; - - _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); - _gl.uniform2f( uniforms.scale, scale.x, scale.y ); - _gl.uniform1f( uniforms.rotation, sprite.rotation ); - - _gl.uniform1f( uniforms.opacity, sprite.opacity ); - _gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b ); - - _renderer.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); - _renderer.setTexture( sprite.texture, 1 ); - - _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); - - } - - } - - } - - } - - // restore gl - - _gl.enable( _gl.CULL_FACE ); - _gl.enable( _gl.DEPTH_TEST ); - _gl.depthMask( true ); - - }; - - function createProgram ( shader, precision ) { - - var program = _gl.createProgram(); - - var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER ); - var vertexShader = _gl.createShader( _gl.VERTEX_SHADER ); - - var prefix = "precision " + precision + " float;\n"; - - _gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); - _gl.shaderSource( vertexShader, prefix + shader.vertexShader ); - - _gl.compileShader( fragmentShader ); - _gl.compileShader( vertexShader ); - - _gl.attachShader( program, fragmentShader ); - _gl.attachShader( program, vertexShader ); - - _gl.linkProgram( program ); - - return program; - - }; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.ShadowMapPlugin = function () { - - var _gl, - _renderer, - _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, - - _frustum = new THREE.Frustum(), - _projScreenMatrix = new THREE.Matrix4(), - - _min = new THREE.Vector3(), - _max = new THREE.Vector3(), - - _matrixPosition = new THREE.Vector3(); - - this.init = function ( renderer ) { - - _gl = renderer.context; - _renderer = renderer; - - var depthShader = THREE.ShaderLib[ "depthRGBA" ]; - var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); - - _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); - _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); - _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); - _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); - - _depthMaterial._shadowPass = true; - _depthMaterialMorph._shadowPass = true; - _depthMaterialSkin._shadowPass = true; - _depthMaterialMorphSkin._shadowPass = true; - - }; - - this.render = function ( scene, camera ) { - - if ( ! ( _renderer.shadowMapEnabled && _renderer.shadowMapAutoUpdate ) ) return; - - this.update( scene, camera ); - - }; - - this.update = function ( scene, camera ) { - - var i, il, j, jl, n, - - shadowMap, shadowMatrix, shadowCamera, - program, buffer, material, - webglObject, object, light, - renderList, - - lights = [], - k = 0, - - fog = null; - - // set GL state for depth map - - _gl.clearColor( 1, 1, 1, 1 ); - _gl.disable( _gl.BLEND ); - - _gl.enable( _gl.CULL_FACE ); - _gl.frontFace( _gl.CCW ); - - if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { - - _gl.cullFace( _gl.FRONT ); - - } else { - - _gl.cullFace( _gl.BACK ); - - } - - _renderer.setDepthTest( true ); - - // preprocess lights - // - skip lights that are not casting shadows - // - create virtual lights for cascaded shadow maps - - for ( i = 0, il = scene.__lights.length; i < il; i ++ ) { - - light = scene.__lights[ i ]; - - if ( ! light.castShadow ) continue; - - if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) { - - for ( n = 0; n < light.shadowCascadeCount; n ++ ) { - - var virtualLight; - - if ( ! light.shadowCascadeArray[ n ] ) { - - virtualLight = createVirtualLight( light, n ); - virtualLight.originalCamera = camera; - - var gyro = new THREE.Gyroscope(); - gyro.position = light.shadowCascadeOffset; - - gyro.add( virtualLight ); - gyro.add( virtualLight.target ); - - camera.add( gyro ); - - light.shadowCascadeArray[ n ] = virtualLight; - - //console.log( "Created virtualLight", virtualLight ); - - } else { - - virtualLight = light.shadowCascadeArray[ n ]; - - } - - updateVirtualLight( light, n ); - - lights[ k ] = virtualLight; - k ++; - - } - - } else { - - lights[ k ] = light; - k ++; - - } - - } - - // render depth map - - for ( i = 0, il = lights.length; i < il; i ++ ) { - - light = lights[ i ]; - - if ( ! light.shadowMap ) { - - var shadowFilter = THREE.NearestFilter; - - if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) { - - shadowFilter = THREE.NearestFilter; - - } - - var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat }; - - light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars ); - light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight ); - - light.shadowMatrix = new THREE.Matrix4(); - - } - - if ( ! light.shadowCamera ) { - - if ( light instanceof THREE.SpotLight ) { - - light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar ); - - } else if ( light instanceof THREE.DirectionalLight ) { - - light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar ); - - } else { - - THREE.onerror( "Unsupported light type for shadow" ); - continue; - - } - - scene.add( light.shadowCamera ); - - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - - } - - if ( light.shadowCameraVisible && ! light.cameraHelper ) { - - light.cameraHelper = new THREE.CameraHelper( light.shadowCamera ); - light.shadowCamera.add( light.cameraHelper ); - - } - - if ( light.isVirtual && virtualLight.originalCamera == camera ) { - - updateShadowCamera( camera, light ); - - } - - shadowMap = light.shadowMap; - shadowMatrix = light.shadowMatrix; - shadowCamera = light.shadowCamera; - - shadowCamera.position.setFromMatrixPosition( light.matrixWorld ); - _matrixPosition.setFromMatrixPosition( light.target.matrixWorld ); - shadowCamera.lookAt( _matrixPosition ); - shadowCamera.updateMatrixWorld(); - - shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); - - if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible; - if ( light.shadowCameraVisible ) light.cameraHelper.update(); - - // compute shadow matrix - - shadowMatrix.set( 0.5, 0.0, 0.0, 0.5, - 0.0, 0.5, 0.0, 0.5, - 0.0, 0.0, 0.5, 0.5, - 0.0, 0.0, 0.0, 1.0 ); - - shadowMatrix.multiply( shadowCamera.projectionMatrix ); - shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); - - // update camera matrices and frustum - - _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); - - // render shadow map - - _renderer.setRenderTarget( shadowMap ); - _renderer.clear(); - - // set object matrices & frustum culling - - renderList = scene.__webglObjects; - - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { - - webglObject = renderList[ j ]; - object = webglObject.object; - - webglObject.render = false; - - if ( object.visible && object.castShadow ) { - - if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { - - object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); - - webglObject.render = true; - - } - - } - - } - - // render regular objects - - var objectMaterial, useMorphing, useSkinning; - - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { - - webglObject = renderList[ j ]; - - if ( webglObject.render ) { - - object = webglObject.object; - buffer = webglObject.buffer; - - // culling is overriden globally for all objects - // while rendering depth map - - // need to deal with MeshFaceMaterial somehow - // in that case just use the first of material.materials for now - // (proper solution would require to break objects by materials - // similarly to regular rendering and then set corresponding - // depth materials per each chunk instead of just once per object) - - objectMaterial = getObjectMaterial( object ); - - useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; - useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; - - if ( object.customDepthMaterial ) { - - material = object.customDepthMaterial; - - } else if ( useSkinning ) { - - material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; - - } else if ( useMorphing ) { - - material = _depthMaterialMorph; - - } else { - - material = _depthMaterial; - - } - - if ( buffer instanceof THREE.BufferGeometry ) { - - _renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object ); - - } else { - - _renderer.renderBuffer( shadowCamera, scene.__lights, fog, material, buffer, object ); - - } - - } - - } - - // set matrices and render immediate objects - - renderList = scene.__webglObjectsImmediate; - - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { - - webglObject = renderList[ j ]; - object = webglObject.object; - - if ( object.visible && object.castShadow ) { - - object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); - - _renderer.renderImmediateObject( shadowCamera, scene.__lights, fog, _depthMaterial, object ); - - } - - } - - } - - // restore GL state - - var clearColor = _renderer.getClearColor(), - clearAlpha = _renderer.getClearAlpha(); - - _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); - _gl.enable( _gl.BLEND ); - - if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { - - _gl.cullFace( _gl.BACK ); - - } - - }; - - function createVirtualLight( light, cascade ) { - - var virtualLight = new THREE.DirectionalLight(); - - virtualLight.isVirtual = true; - - virtualLight.onlyShadow = true; - virtualLight.castShadow = true; - - virtualLight.shadowCameraNear = light.shadowCameraNear; - virtualLight.shadowCameraFar = light.shadowCameraFar; - - virtualLight.shadowCameraLeft = light.shadowCameraLeft; - virtualLight.shadowCameraRight = light.shadowCameraRight; - virtualLight.shadowCameraBottom = light.shadowCameraBottom; - virtualLight.shadowCameraTop = light.shadowCameraTop; - - virtualLight.shadowCameraVisible = light.shadowCameraVisible; - - virtualLight.shadowDarkness = light.shadowDarkness; - - virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; - virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ]; - virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ]; - - virtualLight.pointsWorld = []; - virtualLight.pointsFrustum = []; - - var pointsWorld = virtualLight.pointsWorld, - pointsFrustum = virtualLight.pointsFrustum; - - for ( var i = 0; i < 8; i ++ ) { - - pointsWorld[ i ] = new THREE.Vector3(); - pointsFrustum[ i ] = new THREE.Vector3(); - - } - - var nearZ = light.shadowCascadeNearZ[ cascade ]; - var farZ = light.shadowCascadeFarZ[ cascade ]; - - pointsFrustum[ 0 ].set( -1, -1, nearZ ); - pointsFrustum[ 1 ].set( 1, -1, nearZ ); - pointsFrustum[ 2 ].set( -1, 1, nearZ ); - pointsFrustum[ 3 ].set( 1, 1, nearZ ); - - pointsFrustum[ 4 ].set( -1, -1, farZ ); - pointsFrustum[ 5 ].set( 1, -1, farZ ); - pointsFrustum[ 6 ].set( -1, 1, farZ ); - pointsFrustum[ 7 ].set( 1, 1, farZ ); - - return virtualLight; - - } - - // Synchronize virtual light with the original light - - function updateVirtualLight( light, cascade ) { - - var virtualLight = light.shadowCascadeArray[ cascade ]; - - virtualLight.position.copy( light.position ); - virtualLight.target.position.copy( light.target.position ); - virtualLight.lookAt( virtualLight.target ); - - virtualLight.shadowCameraVisible = light.shadowCameraVisible; - virtualLight.shadowDarkness = light.shadowDarkness; - - virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; - - var nearZ = light.shadowCascadeNearZ[ cascade ]; - var farZ = light.shadowCascadeFarZ[ cascade ]; - - var pointsFrustum = virtualLight.pointsFrustum; - - pointsFrustum[ 0 ].z = nearZ; - pointsFrustum[ 1 ].z = nearZ; - pointsFrustum[ 2 ].z = nearZ; - pointsFrustum[ 3 ].z = nearZ; - - pointsFrustum[ 4 ].z = farZ; - pointsFrustum[ 5 ].z = farZ; - pointsFrustum[ 6 ].z = farZ; - pointsFrustum[ 7 ].z = farZ; - - } - - // Fit shadow camera's ortho frustum to camera frustum - - function updateShadowCamera( camera, light ) { - - var shadowCamera = light.shadowCamera, - pointsFrustum = light.pointsFrustum, - pointsWorld = light.pointsWorld; - - _min.set( Infinity, Infinity, Infinity ); - _max.set( -Infinity, -Infinity, -Infinity ); - - for ( var i = 0; i < 8; i ++ ) { - - var p = pointsWorld[ i ]; - - p.copy( pointsFrustum[ i ] ); - THREE.ShadowMapPlugin.__projector.unprojectVector( p, camera ); - - p.applyMatrix4( shadowCamera.matrixWorldInverse ); - - if ( p.x < _min.x ) _min.x = p.x; - if ( p.x > _max.x ) _max.x = p.x; - - if ( p.y < _min.y ) _min.y = p.y; - if ( p.y > _max.y ) _max.y = p.y; - - if ( p.z < _min.z ) _min.z = p.z; - if ( p.z > _max.z ) _max.z = p.z; - - } - - shadowCamera.left = _min.x; - shadowCamera.right = _max.x; - shadowCamera.top = _max.y; - shadowCamera.bottom = _min.y; - - // can't really fit near/far - //shadowCamera.near = _min.z; - //shadowCamera.far = _max.z; - - shadowCamera.updateProjectionMatrix(); - - } - - // For the moment just ignore objects that have multiple materials with different animation methods - // Only the first material will be taken into account for deciding which depth material to use for shadow maps - - function getObjectMaterial( object ) { - - return object.material instanceof THREE.MeshFaceMaterial - ? object.material.materials[ 0 ] - : object.material; - - }; - -}; - -THREE.ShadowMapPlugin.__projector = new THREE.Projector(); - -/** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.SpritePlugin = function () { - - var _gl, _renderer, _texture; - - var vertices, faces, vertexBuffer, elementBuffer; - var program, attributes, uniforms; - - this.init = function ( renderer ) { - - _gl = renderer.context; - _renderer = renderer; - - vertices = new Float32Array( [ - - 0.5, - 0.5, 0, 0, - 0.5, - 0.5, 1, 0, - 0.5, 0.5, 1, 1, - - 0.5, 0.5, 0, 1 - ] ); - - faces = new Uint16Array( [ - 0, 1, 2, - 0, 2, 3 - ] ); - - vertexBuffer = _gl.createBuffer(); - elementBuffer = _gl.createBuffer(); - - _gl.bindBuffer( _gl.ARRAY_BUFFER, vertexBuffer ); - _gl.bufferData( _gl.ARRAY_BUFFER, vertices, _gl.STATIC_DRAW ); - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faces, _gl.STATIC_DRAW ); - - program = createProgram(); - - attributes = { - position: _gl.getAttribLocation ( program, 'position' ), - uv: _gl.getAttribLocation ( program, 'uv' ) - }; - - uniforms = { - uvOffset: _gl.getUniformLocation( program, 'uvOffset' ), - uvScale: _gl.getUniformLocation( program, 'uvScale' ), - - rotation: _gl.getUniformLocation( program, 'rotation' ), - scale: _gl.getUniformLocation( program, 'scale' ), - - color: _gl.getUniformLocation( program, 'color' ), - map: _gl.getUniformLocation( program, 'map' ), - opacity: _gl.getUniformLocation( program, 'opacity' ), - - modelViewMatrix: _gl.getUniformLocation( program, 'modelViewMatrix' ), - projectionMatrix: _gl.getUniformLocation( program, 'projectionMatrix' ), - - fogType: _gl.getUniformLocation( program, 'fogType' ), - fogDensity: _gl.getUniformLocation( program, 'fogDensity' ), - fogNear: _gl.getUniformLocation( program, 'fogNear' ), - fogFar: _gl.getUniformLocation( program, 'fogFar' ), - fogColor: _gl.getUniformLocation( program, 'fogColor' ), - - alphaTest: _gl.getUniformLocation( program, 'alphaTest' ) - }; - - var canvas = document.createElement( 'canvas' ); - canvas.width = 8; - canvas.height = 8; - - var context = canvas.getContext( '2d' ); - context.fillStyle = '#ffffff'; - context.fillRect( 0, 0, canvas.width, canvas.height ); - - _texture = new THREE.Texture( canvas ); - _texture.needsUpdate = true; - - }; - - this.render = function ( scene, camera, viewportWidth, viewportHeight ) { - - var sprites = scene.__webglSprites, - nSprites = sprites.length; - - if ( ! nSprites ) return; - - // setup gl - - _gl.useProgram( program ); - - _gl.enableVertexAttribArray( attributes.position ); - _gl.enableVertexAttribArray( attributes.uv ); - - _gl.disable( _gl.CULL_FACE ); - _gl.enable( _gl.BLEND ); - - _gl.bindBuffer( _gl.ARRAY_BUFFER, vertexBuffer ); - _gl.vertexAttribPointer( attributes.position, 2, _gl.FLOAT, false, 2 * 8, 0 ); - _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 ); - - _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); - - _gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); - - _gl.activeTexture( _gl.TEXTURE0 ); - _gl.uniform1i( uniforms.map, 0 ); - - var oldFogType = 0; - var sceneFogType = 0; - var fog = scene.fog; - - if ( fog ) { - - _gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); - - if ( fog instanceof THREE.Fog ) { - - _gl.uniform1f( uniforms.fogNear, fog.near ); - _gl.uniform1f( uniforms.fogFar, fog.far ); - - _gl.uniform1i( uniforms.fogType, 1 ); - oldFogType = 1; - sceneFogType = 1; - - } else if ( fog instanceof THREE.FogExp2 ) { - - _gl.uniform1f( uniforms.fogDensity, fog.density ); - - _gl.uniform1i( uniforms.fogType, 2 ); - oldFogType = 2; - sceneFogType = 2; - - } - - } else { - - _gl.uniform1i( uniforms.fogType, 0 ); - oldFogType = 0; - sceneFogType = 0; - - } - - - // update positions and sort - - var i, sprite, material, fogType, scale = []; - - for( i = 0; i < nSprites; i ++ ) { - - sprite = sprites[ i ]; - material = sprite.material; - - if ( sprite.visible === false ) continue; - - sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); - sprite.z = - sprite._modelViewMatrix.elements[ 14 ]; - - } - - sprites.sort( painterSortStable ); - - // render all sprites - - for( i = 0; i < nSprites; i ++ ) { - - sprite = sprites[ i ]; - - if ( sprite.visible === false ) continue; - - material = sprite.material; - - _gl.uniform1f( uniforms.alphaTest, material.alphaTest ); - _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements ); - - scale[ 0 ] = sprite.scale.x; - scale[ 1 ] = sprite.scale.y; - - if ( scene.fog && material.fog ) { - - fogType = sceneFogType; - - } else { - - fogType = 0; - - } - - if ( oldFogType !== fogType ) { - - _gl.uniform1i( uniforms.fogType, fogType ); - oldFogType = fogType; - - } - - if ( material.map !== null ) { - - _gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y ); - _gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y ); - - } else { - - _gl.uniform2f( uniforms.uvOffset, 0, 0 ); - _gl.uniform2f( uniforms.uvScale, 1, 1 ); - - } - - _gl.uniform1f( uniforms.opacity, material.opacity ); - _gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); - - _gl.uniform1f( uniforms.rotation, material.rotation ); - _gl.uniform2fv( uniforms.scale, scale ); - - _renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); - _renderer.setDepthTest( material.depthTest ); - _renderer.setDepthWrite( material.depthWrite ); - - if ( material.map && material.map.image && material.map.image.width ) { - - _renderer.setTexture( material.map, 0 ); - - } else { - - _renderer.setTexture( _texture, 0 ); - - } - - _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); - - } - - // restore gl - - _gl.enable( _gl.CULL_FACE ); - - }; - - function createProgram () { - - var program = _gl.createProgram(); - - var vertexShader = _gl.createShader( _gl.VERTEX_SHADER ); - var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER ); - - _gl.shaderSource( vertexShader, [ - - 'precision ' + _renderer.getPrecision() + ' float;', - - 'uniform mat4 modelViewMatrix;', - 'uniform mat4 projectionMatrix;', - 'uniform float rotation;', - 'uniform vec2 scale;', - 'uniform vec2 uvOffset;', - 'uniform vec2 uvScale;', - - 'attribute vec2 position;', - 'attribute vec2 uv;', - - 'varying vec2 vUV;', - - 'void main() {', - - 'vUV = uvOffset + uv * uvScale;', - - 'vec2 alignedPosition = position * scale;', - - 'vec2 rotatedPosition;', - 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;', - 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;', - - 'vec4 finalPosition;', - - 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );', - 'finalPosition.xy += rotatedPosition;', - 'finalPosition = projectionMatrix * finalPosition;', - - 'gl_Position = finalPosition;', - - '}' - - ].join( '\n' ) ); - - _gl.shaderSource( fragmentShader, [ - - 'precision ' + _renderer.getPrecision() + ' float;', - - 'uniform vec3 color;', - 'uniform sampler2D map;', - 'uniform float opacity;', - - 'uniform int fogType;', - 'uniform vec3 fogColor;', - 'uniform float fogDensity;', - 'uniform float fogNear;', - 'uniform float fogFar;', - 'uniform float alphaTest;', - - 'varying vec2 vUV;', - - 'void main() {', - - 'vec4 texture = texture2D( map, vUV );', - - 'if ( texture.a < alphaTest ) discard;', - - 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', - - 'if ( fogType > 0 ) {', - - 'float depth = gl_FragCoord.z / gl_FragCoord.w;', - 'float fogFactor = 0.0;', - - 'if ( fogType == 1 ) {', - - 'fogFactor = smoothstep( fogNear, fogFar, depth );', - - '} else {', - - 'const float LOG2 = 1.442695;', - 'float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );', - 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', - - '}', - - 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );', - - '}', - - '}' - - ].join( '\n' ) ); - - _gl.compileShader( vertexShader ); - _gl.compileShader( fragmentShader ); - - _gl.attachShader( program, vertexShader ); - _gl.attachShader( program, fragmentShader ); - - _gl.linkProgram( program ); - - return program; - - }; - - function painterSortStable ( a, b ) { - - if ( a.z !== b.z ) { - - return b.z - a.z; - - } else { - - return b.id - a.id; - - } - - }; - -}; - -/** - * @author alteredq / http://alteredqualia.com/ - */ - -THREE.DepthPassPlugin = function () { - - this.enabled = false; - this.renderTarget = null; - - var _gl, - _renderer, - _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, - - _frustum = new THREE.Frustum(), - _projScreenMatrix = new THREE.Matrix4(); - - this.init = function ( renderer ) { - - _gl = renderer.context; - _renderer = renderer; - - var depthShader = THREE.ShaderLib[ "depthRGBA" ]; - var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); - - _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); - _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); - _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); - _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); - - _depthMaterial._shadowPass = true; - _depthMaterialMorph._shadowPass = true; - _depthMaterialSkin._shadowPass = true; - _depthMaterialMorphSkin._shadowPass = true; - - }; - - this.render = function ( scene, camera ) { - - if ( ! this.enabled ) return; - - this.update( scene, camera ); - - }; - - this.update = function ( scene, camera ) { - - var i, il, j, jl, n, - - program, buffer, material, - webglObject, object, light, - renderList, - - fog = null; - - // set GL state for depth map - - _gl.clearColor( 1, 1, 1, 1 ); - _gl.disable( _gl.BLEND ); - - _renderer.setDepthTest( true ); - - // update scene - - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - - // update camera matrices and frustum - - camera.matrixWorldInverse.getInverse( camera.matrixWorld ); - - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); - - // render depth map - - _renderer.setRenderTarget( this.renderTarget ); - _renderer.clear(); - - // set object matrices & frustum culling - - renderList = scene.__webglObjects; - - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { - - webglObject = renderList[ j ]; - object = webglObject.object; - - webglObject.render = false; - - if ( object.visible ) { - - if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { - - object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - - webglObject.render = true; - - } - - } - - } - - // render regular objects - - var objectMaterial, useMorphing, useSkinning; - - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { - - webglObject = renderList[ j ]; - - if ( webglObject.render ) { - - object = webglObject.object; - buffer = webglObject.buffer; - - // todo: create proper depth material for particles - - if ( object instanceof THREE.ParticleSystem && !object.customDepthMaterial ) continue; - - objectMaterial = getObjectMaterial( object ); - - if ( objectMaterial ) _renderer.setMaterialFaces( object.material ); - - useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; - useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; - - if ( object.customDepthMaterial ) { - - material = object.customDepthMaterial; - - } else if ( useSkinning ) { - - material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; - - } else if ( useMorphing ) { - - material = _depthMaterialMorph; - - } else { - - material = _depthMaterial; - - } - - if ( buffer instanceof THREE.BufferGeometry ) { - - _renderer.renderBufferDirect( camera, scene.__lights, fog, material, buffer, object ); - - } else { - - _renderer.renderBuffer( camera, scene.__lights, fog, material, buffer, object ); - - } - - } - - } - - // set matrices and render immediate objects - - renderList = scene.__webglObjectsImmediate; - - for ( j = 0, jl = renderList.length; j < jl; j ++ ) { - - webglObject = renderList[ j ]; - object = webglObject.object; - - if ( object.visible ) { - - object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - - _renderer.renderImmediateObject( camera, scene.__lights, fog, _depthMaterial, object ); - - } - - } - - // restore GL state - - var clearColor = _renderer.getClearColor(), - clearAlpha = _renderer.getClearAlpha(); - - _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); - _gl.enable( _gl.BLEND ); - - }; - - // For the moment just ignore objects that have multiple materials with different animation methods - // Only the first material will be taken into account for deciding which depth material to use - - function getObjectMaterial( object ) { - - return object.material instanceof THREE.MeshFaceMaterial - ? object.material.materials[ 0 ] - : object.material; - - }; - -}; - - -/** - * @author mikael emtinger / http://gomo.se/ - */ - -THREE.ShaderFlares = { - - 'lensFlareVertexTexture': { - - vertexShader: [ - - "uniform lowp int renderType;", - - "uniform vec3 screenPosition;", - "uniform vec2 scale;", - "uniform float rotation;", - - "uniform sampler2D occlusionMap;", - - "attribute vec2 position;", - "attribute vec2 uv;", - - "varying vec2 vUV;", - "varying float vVisibility;", - - "void main() {", - - "vUV = uv;", - - "vec2 pos = position;", - - "if( renderType == 2 ) {", - - "vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );", - "visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );", - - "vVisibility = visibility.r / 9.0;", - "vVisibility *= 1.0 - visibility.g / 9.0;", - "vVisibility *= visibility.b / 9.0;", - "vVisibility *= 1.0 - visibility.a / 9.0;", - - "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", - "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", - - "}", - - "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", - - "}" - - ].join( "\n" ), - - fragmentShader: [ - - "uniform lowp int renderType;", - - "uniform sampler2D map;", - "uniform float opacity;", - "uniform vec3 color;", - - "varying vec2 vUV;", - "varying float vVisibility;", - - "void main() {", - - // pink square - - "if( renderType == 0 ) {", - - "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", - - // restore - - "} else if( renderType == 1 ) {", - - "gl_FragColor = texture2D( map, vUV );", - - // flare - - "} else {", - - "vec4 texture = texture2D( map, vUV );", - "texture.a *= opacity * vVisibility;", - "gl_FragColor = texture;", - "gl_FragColor.rgb *= color;", - - "}", - - "}" - ].join( "\n" ) - - }, - - - 'lensFlare': { - - vertexShader: [ - - "uniform lowp int renderType;", - - "uniform vec3 screenPosition;", - "uniform vec2 scale;", - "uniform float rotation;", - - "attribute vec2 position;", - "attribute vec2 uv;", - - "varying vec2 vUV;", - - "void main() {", - - "vUV = uv;", - - "vec2 pos = position;", - - "if( renderType == 2 ) {", - - "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", - "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", - - "}", - - "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", - - "}" - - ].join( "\n" ), - - fragmentShader: [ - - "precision mediump float;", - - "uniform lowp int renderType;", - - "uniform sampler2D map;", - "uniform sampler2D occlusionMap;", - "uniform float opacity;", - "uniform vec3 color;", - - "varying vec2 vUV;", - - "void main() {", - - // pink square - - "if( renderType == 0 ) {", - - "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );", - - // restore - - "} else if( renderType == 1 ) {", - - "gl_FragColor = texture2D( map, vUV );", - - // flare - - "} else {", - - "float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;", - "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;", - "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;", - "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;", - "visibility = ( 1.0 - visibility / 4.0 );", - - "vec4 texture = texture2D( map, vUV );", - "texture.a *= opacity * visibility;", - "gl_FragColor = texture;", - "gl_FragColor.rgb *= color;", - - "}", - - "}" - - ].join( "\n" ) - - } - -}; - - -// Export the THREE object for **Node.js**, with -// backwards-compatibility for the old `require()` API. If we're in -// the browser, add `_` as a global object via a string identifier, -// for Closure Compiler "advanced" mode. -if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) { - exports = module.exports = THREE; - } - exports.THREE = THREE; -} else { - this['THREE'] = THREE; -} +var self = self || {};/** + * @author mrdoob / http://mrdoob.com/ + * @author Larry Battle / http://bateru.com/news + * @author bhouston / http://exocortex.com + */ + +var THREE = { REVISION: '66.87' }; + +self.console = self.console || { + + info: function () {}, + log: function () {}, + debug: function () {}, + warn: function () {}, + error: function () {} + +}; + +// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ +// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating + +// requestAnimationFrame polyfill by Erik Möller +// fixes from Paul Irish and Tino Zijdel +// using 'self' instead of 'window' for compatibility with both NodeJS and IE10. +( function () { + + var lastTime = 0; + var vendors = [ 'ms', 'moz', 'webkit', 'o' ]; + + for ( var x = 0; x < vendors.length && !self.requestAnimationFrame; ++ x ) { + + self.requestAnimationFrame = self[ vendors[ x ] + 'RequestAnimationFrame' ]; + self.cancelAnimationFrame = self[ vendors[ x ] + 'CancelAnimationFrame' ] || self[ vendors[ x ] + 'CancelRequestAnimationFrame' ]; + + } + + if ( self.requestAnimationFrame === undefined && self['setTimeout'] !== undefined ) { + + self.requestAnimationFrame = function ( callback ) { + + var currTime = Date.now(), timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ); + var id = self.setTimeout( function() { callback( currTime + timeToCall ); }, timeToCall ); + lastTime = currTime + timeToCall; + return id; + + }; + + } + + if( self.cancelAnimationFrame === undefined && self['clearTimeout'] !== undefined ) { + + self.cancelAnimationFrame = function ( id ) { self.clearTimeout( id ) }; + + } + +}() ); + +THREE.ExceptionErrorHandler = function( message, optionalData ) { + console.error( message ); + console.error( optionalData ); + var error = new Error( message ); + error.optionalData = optionalData; + throw error; +}; + +THREE.ConsoleErrorHandler = function( message, optionalData ) { + console.error( message ); + console.error( optionalData ); +}; + +THREE.ConsoleWarningHandler = function( message, optionalData ) { + console.warn( message ); + console.warn( optionalData ); +}; + +THREE.NullHandler = function( message, optionalData ) { +}; + +// the default error handler is exception +THREE.onerror = THREE.ExceptionErrorHandler; + +THREE.onwarning = THREE.ConsoleWarningHandler; + +// GL STATE CONSTANTS + +THREE.CullFaceNone = 0; +THREE.CullFaceBack = 1; +THREE.CullFaceFront = 2; +THREE.CullFaceFrontBack = 3; + +THREE.FrontFaceDirectionCW = 0; +THREE.FrontFaceDirectionCCW = 1; + +// SHADOWING TYPES + +THREE.BasicShadowMap = 0; +THREE.PCFShadowMap = 1; +THREE.PCFSoftShadowMap = 2; + +// MATERIAL CONSTANTS + +// side + +THREE.FrontSide = 0; +THREE.BackSide = 1; +THREE.DoubleSide = 2; + +// shading + +THREE.NoShading = 0; +THREE.FlatShading = 1; +THREE.SmoothShading = 2; + +// colors + +THREE.NoColors = 0; +THREE.FaceColors = 1; +THREE.VertexColors = 2; + +// blending modes + +THREE.NoBlending = 0; +THREE.NormalBlending = 1; +THREE.AdditiveBlending = 2; +THREE.SubtractiveBlending = 3; +THREE.MultiplyBlending = 4; +THREE.CustomBlending = 5; + +// custom blending equations +// (numbers start from 100 not to clash with other +// mappings to OpenGL constants defined in Texture.js) + +THREE.AddEquation = 100; +THREE.SubtractEquation = 101; +THREE.ReverseSubtractEquation = 102; + +// custom blending destination factors + +THREE.ZeroFactor = 200; +THREE.OneFactor = 201; +THREE.SrcColorFactor = 202; +THREE.OneMinusSrcColorFactor = 203; +THREE.SrcAlphaFactor = 204; +THREE.OneMinusSrcAlphaFactor = 205; +THREE.DstAlphaFactor = 206; +THREE.OneMinusDstAlphaFactor = 207; + +// custom blending source factors + +//THREE.ZeroFactor = 200; +//THREE.OneFactor = 201; +//THREE.SrcAlphaFactor = 204; +//THREE.OneMinusSrcAlphaFactor = 205; +//THREE.DstAlphaFactor = 206; +//THREE.OneMinusDstAlphaFactor = 207; +THREE.DstColorFactor = 208; +THREE.OneMinusDstColorFactor = 209; +THREE.SrcAlphaSaturateFactor = 210; + + +// TEXTURE CONSTANTS + +THREE.MultiplyOperation = 0; +THREE.MixOperation = 1; +THREE.AddOperation = 2; + +// Mapping modes + +THREE.UVMapping = function () {}; + +THREE.CubeReflectionMapping = function () {}; +THREE.CubeRefractionMapping = function () {}; + +THREE.SphericalReflectionMapping = function () {}; +THREE.SphericalRefractionMapping = function () {}; + +// Wrapping modes + +THREE.RepeatWrapping = 1000; +THREE.ClampToEdgeWrapping = 1001; +THREE.MirroredRepeatWrapping = 1002; + +// Filters + +THREE.NearestFilter = 1003; +THREE.NearestMipMapNearestFilter = 1004; +THREE.NearestMipMapLinearFilter = 1005; +THREE.LinearFilter = 1006; +THREE.LinearMipMapNearestFilter = 1007; +THREE.LinearMipMapLinearFilter = 1008; + +// Texture Decoders + +THREE.Linear = 3000; +THREE.sRGB = 3001; +THREE.RGBE = 3002; +THREE.LogLUV = 3003; +THREE.RGBM7 = 3004; +THREE.RGBM16 = 3005; + +// Data types + +THREE.UnsignedByteType = 1009; +THREE.ByteType = 1010; +THREE.ShortType = 1011; +THREE.UnsignedShortType = 1012; +THREE.IntType = 1013; +THREE.UnsignedIntType = 1014; +THREE.FloatType = 1015; +THREE.HalfType = 2005; + +// Pixel types + +//THREE.UnsignedByteType = 1009; +THREE.UnsignedShort4444Type = 1016; +THREE.UnsignedShort5551Type = 1017; +THREE.UnsignedShort565Type = 1018; + +// Pixel formats + +THREE.AlphaFormat = 1019; +THREE.RGBFormat = 1020; +THREE.RGBAFormat = 1021; +THREE.LuminanceFormat = 1022; +THREE.LuminanceAlphaFormat = 1023; + +// Compressed texture formats + +THREE.RGB_S3TC_DXT1_Format = 2001; +THREE.RGBA_S3TC_DXT1_Format = 2002; +THREE.RGBA_S3TC_DXT3_Format = 2003; +THREE.RGBA_S3TC_DXT5_Format = 2004; + +/* +// Potential future PVRTC compressed texture formats +THREE.RGB_PVRTC_4BPPV1_Format = 2100; +THREE.RGB_PVRTC_2BPPV1_Format = 2101; +THREE.RGBA_PVRTC_4BPPV1_Format = 2102; +THREE.RGBA_PVRTC_2BPPV1_Format = 2103; +*/ + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Color = function ( color ) { + + if ( arguments.length === 3 ) { + + return this.setRGB( arguments[ 0 ], arguments[ 1 ], arguments[ 2 ] ); + + } + + return this.set( color ) + +}; + +THREE.Color.prototype = { + + constructor: THREE.Color, + + r: 1, g: 1, b: 1, + + set: function ( value ) { + + if ( value instanceof THREE.Color ) { + + this.copy( value ); + + } else if ( typeof value === 'number' ) { + + this.setHex( value ); + + } else if ( typeof value === 'string' ) { + + this.setStyle( value ); + + } + + return this; + + }, + + setHex: function ( hex ) { + + hex = Math.floor( hex ); + + this.r = ( hex >> 16 & 255 ) / 255; + this.g = ( hex >> 8 & 255 ) / 255; + this.b = ( hex & 255 ) / 255; + + return this; + + }, + + setRGB: function ( r, g, b ) { + + this.r = r; + this.g = g; + this.b = b; + + return this; + + }, + + setHSL: function ( h, s, l ) { + + // h,s,l ranges are in 0.0 - 1.0 + + if ( s === 0 ) { + + this.r = this.g = this.b = l; + + } else { + + var hue2rgb = function ( p, q, t ) { + + if ( t < 0 ) t += 1; + if ( t > 1 ) t -= 1; + if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; + if ( t < 1 / 2 ) return q; + if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); + return p; + + }; + + var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); + var q = ( 2 * l ) - p; + + this.r = hue2rgb( q, p, h + 1 / 3 ); + this.g = hue2rgb( q, p, h ); + this.b = hue2rgb( q, p, h - 1 / 3 ); + + } + + return this; + + }, + + setStyle: function ( style ) { + + // rgb(255,0,0) + + if ( /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test( style ) ) { + + var color = /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec( style ); + + this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; + this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; + this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; + + return this; + + } + + // rgb(100%,0%,0%) + + if ( /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test( style ) ) { + + var color = /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec( style ); + + this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; + this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; + this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; + + return this; + + } + + // #ff0000 + + if ( /^\#([0-9a-f]{6})$/i.test( style ) ) { + + var color = /^\#([0-9a-f]{6})$/i.exec( style ); + + this.setHex( parseInt( color[ 1 ], 16 ) ); + + return this; + + } + + // #f00 + + if ( /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test( style ) ) { + + var color = /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec( style ); + + this.setHex( parseInt( color[ 1 ] + color[ 1 ] + color[ 2 ] + color[ 2 ] + color[ 3 ] + color[ 3 ], 16 ) ); + + return this; + + } + + // red + + if ( /^(\w+)$/i.test( style ) ) { + + this.setHex( THREE.ColorKeywords[ style ] ); + + return this; + + } + + + }, + + copy: function ( color ) { + + this.r = color.r; + this.g = color.g; + this.b = color.b; + + return this; + + }, + + copyGammaToLinear: function ( color ) { + + this.r = color.r * color.r; + this.g = color.g * color.g; + this.b = color.b * color.b; + + return this; + + }, + + copyLinearToGamma: function ( color ) { + + this.r = Math.sqrt( color.r ); + this.g = Math.sqrt( color.g ); + this.b = Math.sqrt( color.b ); + + return this; + + }, + + convertGammaToLinear: function () { + + var r = this.r, g = this.g, b = this.b; + + this.r = r * r; + this.g = g * g; + this.b = b * b; + + return this; + + }, + + convertLinearToGamma: function () { + + this.r = Math.sqrt( this.r ); + this.g = Math.sqrt( this.g ); + this.b = Math.sqrt( this.b ); + + return this; + + }, + + getHex: function () { + + return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; + + }, + + getHexString: function () { + + return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); + + }, + + getHSL: function ( optionalTarget ) { + + // h,s,l ranges are in 0.0 - 1.0 + + var hsl = optionalTarget || { h: 0, s: 0, l: 0 }; + + var r = this.r, g = this.g, b = this.b; + + var max = Math.max( r, g, b ); + var min = Math.min( r, g, b ); + + var hue, saturation; + var lightness = ( min + max ) / 2.0; + + if ( min === max ) { + + hue = 0; + saturation = 0; + + } else { + + var delta = max - min; + + saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); + + switch ( max ) { + + case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; + case g: hue = ( b - r ) / delta + 2; break; + case b: hue = ( r - g ) / delta + 4; break; + + } + + hue /= 6; + + } + + hsl.h = hue; + hsl.s = saturation; + hsl.l = lightness; + + return hsl; + + }, + + getStyle: function () { + + return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; + + }, + + offsetHSL: function ( h, s, l ) { + + var hsl = this.getHSL(); + + hsl.h += h; hsl.s += s; hsl.l += l; + + this.setHSL( hsl.h, hsl.s, hsl.l ); + + return this; + + }, + + add: function ( color ) { + + this.r += color.r; + this.g += color.g; + this.b += color.b; + + return this; + + }, + + addColors: function ( color1, color2 ) { + + this.r = color1.r + color2.r; + this.g = color1.g + color2.g; + this.b = color1.b + color2.b; + + return this; + + }, + + addScalar: function ( s ) { + + this.r += s; + this.g += s; + this.b += s; + + return this; + + }, + + multiply: function ( color ) { + + this.r *= color.r; + this.g *= color.g; + this.b *= color.b; + + return this; + + }, + + multiplyScalar: function ( s ) { + + this.r *= s; + this.g *= s; + this.b *= s; + + return this; + + }, + + lerp: function ( color, alpha ) { + + this.r += ( color.r - this.r ) * alpha; + this.g += ( color.g - this.g ) * alpha; + this.b += ( color.b - this.b ) * alpha; + + return this; + + }, + + equals: function ( c ) { + + return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); + + }, + + fromArray: function ( array ) { + + this.r = array[ 0 ]; + this.g = array[ 1 ]; + this.b = array[ 2 ]; + + return this; + + }, + + toArray: function () { + + return [ this.r, this.g, this.b ]; + + }, + + clone: function () { + + return new THREE.Color().setRGB( this.r, this.g, this.b ); + + } + +}; + +THREE.ColorKeywords = { "aliceblue": 0xF0F8FF, "antiquewhite": 0xFAEBD7, "aqua": 0x00FFFF, "aquamarine": 0x7FFFD4, "azure": 0xF0FFFF, +"beige": 0xF5F5DC, "bisque": 0xFFE4C4, "black": 0x000000, "blanchedalmond": 0xFFEBCD, "blue": 0x0000FF, "blueviolet": 0x8A2BE2, +"brown": 0xA52A2A, "burlywood": 0xDEB887, "cadetblue": 0x5F9EA0, "chartreuse": 0x7FFF00, "chocolate": 0xD2691E, "coral": 0xFF7F50, +"cornflowerblue": 0x6495ED, "cornsilk": 0xFFF8DC, "crimson": 0xDC143C, "cyan": 0x00FFFF, "darkblue": 0x00008B, "darkcyan": 0x008B8B, +"darkgoldenrod": 0xB8860B, "darkgray": 0xA9A9A9, "darkgreen": 0x006400, "darkgrey": 0xA9A9A9, "darkkhaki": 0xBDB76B, "darkmagenta": 0x8B008B, +"darkolivegreen": 0x556B2F, "darkorange": 0xFF8C00, "darkorchid": 0x9932CC, "darkred": 0x8B0000, "darksalmon": 0xE9967A, "darkseagreen": 0x8FBC8F, +"darkslateblue": 0x483D8B, "darkslategray": 0x2F4F4F, "darkslategrey": 0x2F4F4F, "darkturquoise": 0x00CED1, "darkviolet": 0x9400D3, +"deeppink": 0xFF1493, "deepskyblue": 0x00BFFF, "dimgray": 0x696969, "dimgrey": 0x696969, "dodgerblue": 0x1E90FF, "firebrick": 0xB22222, +"floralwhite": 0xFFFAF0, "forestgreen": 0x228B22, "fuchsia": 0xFF00FF, "gainsboro": 0xDCDCDC, "ghostwhite": 0xF8F8FF, "gold": 0xFFD700, +"goldenrod": 0xDAA520, "gray": 0x808080, "green": 0x008000, "greenyellow": 0xADFF2F, "grey": 0x808080, "honeydew": 0xF0FFF0, "hotpink": 0xFF69B4, +"indianred": 0xCD5C5C, "indigo": 0x4B0082, "ivory": 0xFFFFF0, "khaki": 0xF0E68C, "lavender": 0xE6E6FA, "lavenderblush": 0xFFF0F5, "lawngreen": 0x7CFC00, +"lemonchiffon": 0xFFFACD, "lightblue": 0xADD8E6, "lightcoral": 0xF08080, "lightcyan": 0xE0FFFF, "lightgoldenrodyellow": 0xFAFAD2, "lightgray": 0xD3D3D3, +"lightgreen": 0x90EE90, "lightgrey": 0xD3D3D3, "lightpink": 0xFFB6C1, "lightsalmon": 0xFFA07A, "lightseagreen": 0x20B2AA, "lightskyblue": 0x87CEFA, +"lightslategray": 0x778899, "lightslategrey": 0x778899, "lightsteelblue": 0xB0C4DE, "lightyellow": 0xFFFFE0, "lime": 0x00FF00, "limegreen": 0x32CD32, +"linen": 0xFAF0E6, "magenta": 0xFF00FF, "maroon": 0x800000, "mediumaquamarine": 0x66CDAA, "mediumblue": 0x0000CD, "mediumorchid": 0xBA55D3, +"mediumpurple": 0x9370DB, "mediumseagreen": 0x3CB371, "mediumslateblue": 0x7B68EE, "mediumspringgreen": 0x00FA9A, "mediumturquoise": 0x48D1CC, +"mediumvioletred": 0xC71585, "midnightblue": 0x191970, "mintcream": 0xF5FFFA, "mistyrose": 0xFFE4E1, "moccasin": 0xFFE4B5, "navajowhite": 0xFFDEAD, +"navy": 0x000080, "oldlace": 0xFDF5E6, "olive": 0x808000, "olivedrab": 0x6B8E23, "orange": 0xFFA500, "orangered": 0xFF4500, "orchid": 0xDA70D6, +"palegoldenrod": 0xEEE8AA, "palegreen": 0x98FB98, "paleturquoise": 0xAFEEEE, "palevioletred": 0xDB7093, "papayawhip": 0xFFEFD5, "peachpuff": 0xFFDAB9, +"peru": 0xCD853F, "pink": 0xFFC0CB, "plum": 0xDDA0DD, "powderblue": 0xB0E0E6, "purple": 0x800080, "red": 0xFF0000, "rosybrown": 0xBC8F8F, +"royalblue": 0x4169E1, "saddlebrown": 0x8B4513, "salmon": 0xFA8072, "sandybrown": 0xF4A460, "seagreen": 0x2E8B57, "seashell": 0xFFF5EE, +"sienna": 0xA0522D, "silver": 0xC0C0C0, "skyblue": 0x87CEEB, "slateblue": 0x6A5ACD, "slategray": 0x708090, "slategrey": 0x708090, "snow": 0xFFFAFA, +"springgreen": 0x00FF7F, "steelblue": 0x4682B4, "tan": 0xD2B48C, "teal": 0x008080, "thistle": 0xD8BFD8, "tomato": 0xFF6347, "turquoise": 0x40E0D0, +"violet": 0xEE82EE, "wheat": 0xF5DEB3, "white": 0xFFFFFF, "whitesmoke": 0xF5F5F5, "yellow": 0xFFFF00, "yellowgreen": 0x9ACD32 }; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://exocortex.com + */ + +THREE.Quaternion = function ( x, y, z, w ) { + + this._x = x || 0; + this._y = y || 0; + this._z = z || 0; + this._w = ( w !== undefined ) ? w : 1; + +}; + +THREE.Quaternion.prototype = { + + constructor: THREE.Quaternion, + + _x: 0,_y: 0, _z: 0, _w: 0, + + _euler: undefined, + + _updateEuler: function ( callback ) { + + if ( this._euler !== undefined ) { + + this._euler.setFromQuaternion( this, undefined, false ); + + } + + }, + + get x () { + + return this._x; + + }, + + set x ( value ) { + + this._x = value; + this._updateEuler(); + + }, + + get y () { + + return this._y; + + }, + + set y ( value ) { + + this._y = value; + this._updateEuler(); + + }, + + get z () { + + return this._z; + + }, + + set z ( value ) { + + this._z = value; + this._updateEuler(); + + }, + + get w () { + + return this._w; + + }, + + set w ( value ) { + + this._w = value; + this._updateEuler(); + + }, + + set: function ( x, y, z, w ) { + + this._x = x; + this._y = y; + this._z = z; + this._w = w; + + this._updateEuler(); + + return this; + + }, + + copy: function ( quaternion ) { + + this._x = quaternion._x; + this._y = quaternion._y; + this._z = quaternion._z; + this._w = quaternion._w; + + this._updateEuler(); + + return this; + + }, + + setFromEuler: function ( euler, update ) { + + if ( ! ( euler instanceof THREE.Euler ) ) return THREE.onerror( 'expecting a Euler', euler ); + + // http://www.mathworks.com/matlabcentral/fileexchange/ + // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ + // content/SpinCalc.m + + var c1 = Math.cos( euler._x / 2 ); + var c2 = Math.cos( euler._y / 2 ); + var c3 = Math.cos( euler._z / 2 ); + var s1 = Math.sin( euler._x / 2 ); + var s2 = Math.sin( euler._y / 2 ); + var s3 = Math.sin( euler._z / 2 ); + + if ( euler.order === 'XYZ' ) { + + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + + } else if ( euler.order === 'YXZ' ) { + + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + + } else if ( euler.order === 'ZXY' ) { + + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + + } else if ( euler.order === 'ZYX' ) { + + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + + } else if ( euler.order === 'YZX' ) { + + this._x = s1 * c2 * c3 + c1 * s2 * s3; + this._y = c1 * s2 * c3 + s1 * c2 * s3; + this._z = c1 * c2 * s3 - s1 * s2 * c3; + this._w = c1 * c2 * c3 - s1 * s2 * s3; + + } else if ( euler.order === 'XZY' ) { + + this._x = s1 * c2 * c3 - c1 * s2 * s3; + this._y = c1 * s2 * c3 - s1 * c2 * s3; + this._z = c1 * c2 * s3 + s1 * s2 * c3; + this._w = c1 * c2 * c3 + s1 * s2 * s3; + + } + + if ( update !== false ) this._updateEuler(); + + return this; + + }, + + setFromAxisAngle: function ( axis, angle ) { + + // from http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + // axis have to be normalized + + var halfAngle = angle / 2, s = Math.sin( halfAngle ); + + this._x = axis.x * s; + this._y = axis.y * s; + this._z = axis.z * s; + this._w = Math.cos( halfAngle ); + + this._updateEuler(); + + return this; + + }, + + setFromRotationMatrix: function ( m ) { + + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + var te = m.elements, + + m11 = te[0], m12 = te[4], m13 = te[8], + m21 = te[1], m22 = te[5], m23 = te[9], + m31 = te[2], m32 = te[6], m33 = te[10], + + trace = m11 + m22 + m33, + s; + + if ( trace > 0 ) { + + s = 0.5 / Math.sqrt( trace + 1.0 ); + + this._w = 0.25 / s; + this._x = ( m32 - m23 ) * s; + this._y = ( m13 - m31 ) * s; + this._z = ( m21 - m12 ) * s; + + } else if ( m11 > m22 && m11 > m33 ) { + + s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); + + this._w = (m32 - m23 ) / s; + this._x = 0.25 * s; + this._y = (m12 + m21 ) / s; + this._z = (m13 + m31 ) / s; + + } else if ( m22 > m33 ) { + + s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); + + this._w = (m13 - m31 ) / s; + this._x = (m12 + m21 ) / s; + this._y = 0.25 * s; + this._z = (m23 + m32 ) / s; + + } else { + + s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); + + this._w = ( m21 - m12 ) / s; + this._x = ( m13 + m31 ) / s; + this._y = ( m23 + m32 ) / s; + this._z = 0.25 * s; + + } + + this._updateEuler(); + + return this; + + }, + + inverse: function () { + + this.conjugate().normalize(); + + return this; + + }, + + add: function ( q ) { + + this._x += q._x; + this._y += q._y; + this._z += q._z; + this._w += q._w; + + return this; + + }, + + sub: function ( q ) { + + this._x -= q._x; + this._y -= q._y; + this._z -= q._z; + this._w -= q._w; + + return this; + + }, + + multiplyScalar: function ( s ) { + + this._x *= s; + this._y *= s; + this._z *= s; + this._w *= s; + + return this; + + }, + + conjugate: function () { + + this._x *= -1; + this._y *= -1; + this._z *= -1; + + this._updateEuler(); + + return this; + + }, + + lengthSq: function () { + + return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; + + }, + + length: function () { + + return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); + + }, + + normalize: function () { + + var l = this.length(); + + if ( l === 0 ) { + + this._x = 0; + this._y = 0; + this._z = 0; + this._w = 1; + + } else { + + l = 1 / l; + + this._x = this._x * l; + this._y = this._y * l; + this._z = this._z * l; + this._w = this._w * l; + + } + + return this; + + }, + + multiply: function ( q, p ) { + + if ( p !== undefined ) { + + THREE.onwarning( 'DEPRECATED: Quaternion\'s .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); + return this.multiplyQuaternions( q, p ); + + } + + return this.multiplyQuaternions( this, q ); + + }, + + multiplyQuaternions: function ( a, b ) { + + // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm + + var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; + var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; + + this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + + this._updateEuler(); + + return this; + + }, + + multiplyVector3: function ( vector ) { + + THREE.onwarning( 'DEPRECATED: Quaternion\'s .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); + return vector.applyQuaternion( this ); + + }, + + slerp: function ( qb, t ) { + + var x = this._x, y = this._y, z = this._z, w = this._w; + + // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ + + var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; + + if ( cosHalfTheta < 0 ) { + + this._w = -qb._w; + this._x = -qb._x; + this._y = -qb._y; + this._z = -qb._z; + + cosHalfTheta = -cosHalfTheta; + + } else { + + this.copy( qb ); + + } + + if ( cosHalfTheta >= 1.0 ) { + + this._w = w; + this._x = x; + this._y = y; + this._z = z; + + return this; + + } + + var halfTheta = Math.acos( cosHalfTheta ); + var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta ); + + if ( Math.abs( sinHalfTheta ) < 0.001 ) { + + this._w = 0.5 * ( w + this._w ); + this._x = 0.5 * ( x + this._x ); + this._y = 0.5 * ( y + this._y ); + this._z = 0.5 * ( z + this._z ); + + return this; + + } + + var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, + ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; + + this._w = ( w * ratioA + this._w * ratioB ); + this._x = ( x * ratioA + this._x * ratioB ); + this._y = ( y * ratioA + this._y * ratioB ); + this._z = ( z * ratioA + this._z * ratioB ); + + this._updateEuler(); + + return this; + + }, + + equals: function ( quaternion ) { + + return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); + + }, + + fromArray: function ( array ) { + + this._x = array[ 0 ]; + this._y = array[ 1 ]; + this._z = array[ 2 ]; + this._w = array[ 3 ]; + + this._updateEuler(); + + return this; + + }, + + toArray: function () { + + return [ this._x, this._y, this._z, this._w ]; + + }, + + clone: function () { + + return new THREE.Quaternion( this._x, this._y, this._z, this._w ); + + } + +}; + +THREE.Quaternion.slerp = function ( qa, qb, qm, t ) { + + return qm.copy( qa ).slerp( qb, t ); + +} + +/** + * @author mrdoob / http://mrdoob.com/ + * @author philogb / http://blog.thejit.org/ + * @author egraether / http://egraether.com/ + * @author zz85 / http://www.lab4games.net/zz85/blog + */ + +THREE.Vector2 = function ( x, y ) { + + this.x = x || 0; + this.y = y || 0; + +}; + +THREE.Vector2.prototype = { + + constructor: THREE.Vector2, + + set: function ( x, y ) { + + this.x = x; + this.y = y; + + return this; + + }, + + setX: function ( x ) { + + this.x = x; + + return this; + + }, + + setY: function ( y ) { + + this.y = y; + + return this; + + }, + + + setComponent: function ( index, value ) { + + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + default: return THREE.onerror( 'index is out of range: ' + index ); + + } + + }, + + getComponent: function ( index ) { + + switch ( index ) { + + case 0: return this.x; + case 1: return this.y; + default: return THREE.onerror( 'index is out of range: ' + index ); + + } + + }, + + copy: function ( v ) { + + this.x = v.x; + this.y = v.y; + + return this; + + }, + + add: function ( v, w ) { + + if ( w !== undefined ) { + + THREE.onwarning( 'DEPRECATED: Vector2\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); + + } + + this.x += v.x; + this.y += v.y; + + return this; + + }, + + addVectors: function ( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + + return this; + + }, + + addScalar: function ( s ) { + + this.x += s; + this.y += s; + + return this; + + }, + + sub: function ( v, w ) { + + if ( w !== undefined ) { + + THREE.onwarning( 'DEPRECATED: Vector2\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); + + } + + this.x -= v.x; + this.y -= v.y; + + return this; + + }, + + subVectors: function ( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + + return this; + + }, + + multiplyScalar: function ( s ) { + + this.x *= s; + this.y *= s; + + return this; + + }, + + divideScalar: function ( scalar ) { + + if ( scalar !== 0 ) { + + var invScalar = 1 / scalar; + + this.x *= invScalar; + this.y *= invScalar; + + } else { + + this.x = 0; + this.y = 0; + + } + + return this; + + }, + + min: function ( v ) { + + if ( this.x > v.x ) { + + this.x = v.x; + + } + + if ( this.y > v.y ) { + + this.y = v.y; + + } + + return this; + + }, + + max: function ( v ) { + + if ( this.x < v.x ) { + + this.x = v.x; + + } + + if ( this.y < v.y ) { + + this.y = v.y; + + } + + return this; + + }, + + clamp: function ( min, max ) { + + // This function assumes min < max, if this assumption isn't true it will not operate correctly + + if ( this.x < min.x ) { + + this.x = min.x; + + } else if ( this.x > max.x ) { + + this.x = max.x; + + } + + if ( this.y < min.y ) { + + this.y = min.y; + + } else if ( this.y > max.y ) { + + this.y = max.y; + + } + + return this; + }, + + clampScalar: ( function () { + + var min, max; + + return function ( minVal, maxVal ) { + + if ( min === undefined ) { + + min = new THREE.Vector2(); + max = new THREE.Vector2(); + + } + + min.set( minVal, minVal ); + max.set( maxVal, maxVal ); + + return this.clamp( min, max ); + + }; + + } )(), + + floor: function () { + + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + + return this; + + }, + + ceil: function () { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + + return this; + + }, + + round: function () { + + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + + return this; + + }, + + roundToZero: function () { + + this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); + this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + + return this; + + }, + + negate: function () { + + return this.multiplyScalar( - 1 ); + + }, + + dot: function ( v ) { + + return this.x * v.x + this.y * v.y; + + }, + + lengthSq: function () { + + return this.x * this.x + this.y * this.y; + + }, + + length: function () { + + return Math.sqrt( this.x * this.x + this.y * this.y ); + + }, + + normalize: function () { + + return this.divideScalar( this.length() ); + + }, + + distanceTo: function ( v ) { + + return Math.sqrt( this.distanceToSquared( v ) ); + + }, + + distanceToSquared: function ( v ) { + + var dx = this.x - v.x, dy = this.y - v.y; + return dx * dx + dy * dy; + + }, + + setLength: function ( l ) { + + var oldLength = this.length(); + + if ( oldLength !== 0 && l !== oldLength ) { + + this.multiplyScalar( l / oldLength ); + } + + return this; + + }, + + lerp: function ( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + + return this; + + }, + + equals: function( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) ); + + }, + + fromArray: function ( array ) { + + this.x = array[ 0 ]; + this.y = array[ 1 ]; + + return this; + + }, + + toArray: function () { + + return [ this.x, this.y ]; + + }, + + clone: function () { + + return new THREE.Vector2( this.x, this.y ); + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author *kile / http://kile.stravaganza.org/ + * @author philogb / http://blog.thejit.org/ + * @author mikael emtinger / http://gomo.se/ + * @author egraether / http://egraether.com/ + * @author WestLangley / http://github.com/WestLangley + */ + +THREE.Vector3 = function ( x, y, z ) { + + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + +}; + +THREE.Vector3.prototype = { + + constructor: THREE.Vector3, + + set: function ( x, y, z ) { + + this.x = x; + this.y = y; + this.z = z; + + return this; + + }, + + setX: function ( x ) { + + this.x = x; + + return this; + + }, + + setY: function ( y ) { + + this.y = y; + + return this; + + }, + + setZ: function ( z ) { + + this.z = z; + + return this; + + }, + + setComponent: function ( index, value ) { + + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + default: return THREE.onerror( 'index is out of range: ' + index ); + + } + + }, + + getComponent: function ( index ) { + + switch ( index ) { + + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + default: return THREE.onerror( 'index is out of range: ' + index ); + + } + + }, + + copy: function ( v ) { + + this.x = v.x; + this.y = v.y; + this.z = v.z; + + return this; + + }, + + add: function ( v, w ) { + + if ( w !== undefined ) { + + THREE.onwarning( 'DEPRECATED: Vector3\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); + + } + + this.x += v.x; + this.y += v.y; + this.z += v.z; + + return this; + + }, + + addScalar: function ( s ) { + + this.x += s; + this.y += s; + this.z += s; + + return this; + + }, + + addVectors: function ( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + + return this; + + }, + + sub: function ( v, w ) { + + if ( w !== undefined ) { + + THREE.onwarningn( 'DEPRECATED: Vector3\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); + + } + + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + + return this; + + }, + + subVectors: function ( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + + return this; + + }, + + multiply: function ( v, w ) { + + if ( w !== undefined ) { + + THREE.onwarning( 'DEPRECATED: Vector3\'s .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); + return this.multiplyVectors( v, w ); + + } + + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; + + return this; + + }, + + multiplyScalar: function ( scalar ) { + + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + + return this; + + }, + + multiplyVectors: function ( a, b ) { + + this.x = a.x * b.x; + this.y = a.y * b.y; + this.z = a.z * b.z; + + return this; + + }, + + applyEuler: function () { + + var quaternion; + + return function ( euler ) { + + if ( ! ( euler instanceof THREE.Euler ) ) return THREE.onerror( 'expecting an Euler', euler ); + + if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); + + this.applyQuaternion( quaternion.setFromEuler( euler ) ); + + return this; + + }; + + }(), + + applyAxisAngle: function () { + + var quaternion; + + return function ( axis, angle ) { + + if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); + + this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); + + return this; + + }; + + }(), + + applyMatrix3: function ( m ) { + + //if ( ! ( m instanceof THREE.Matrix3 ) ) return THREE.onerror( 'expecting an Matrix3', m ); + + var x = this.x; + var y = this.y; + var z = this.z; + + var e = m.elements; + + this.x = e[0] * x + e[3] * y + e[6] * z; + this.y = e[1] * x + e[4] * y + e[7] * z; + this.z = e[2] * x + e[5] * y + e[8] * z; + + return this; + + }, + + applyMatrix4: function ( m ) { + + // input: THREE.Matrix4 affine matrix + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting an Matrix4', m ); + + var x = this.x, y = this.y, z = this.z; + + var e = m.elements; + + this.x = e[0] * x + e[4] * y + e[8] * z + e[12]; + this.y = e[1] * x + e[5] * y + e[9] * z + e[13]; + this.z = e[2] * x + e[6] * y + e[10] * z + e[14]; + + return this; + + }, + + applyProjection: function ( m ) { + + // input: THREE.Matrix4 projection matrix + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting an Matrix4', m ); + + var x = this.x, y = this.y, z = this.z; + + var e = m.elements; + var d = 1 / ( e[3] * x + e[7] * y + e[11] * z + e[15] ); // perspective divide + + this.x = ( e[0] * x + e[4] * y + e[8] * z + e[12] ) * d; + this.y = ( e[1] * x + e[5] * y + e[9] * z + e[13] ) * d; + this.z = ( e[2] * x + e[6] * y + e[10] * z + e[14] ) * d; + + return this; + + }, + + applyQuaternion: function ( q ) { + + var x = this.x; + var y = this.y; + var z = this.z; + + var qx = q.x; + var qy = q.y; + var qz = q.z; + var qw = q.w; + + // calculate quat * vector + + var ix = qw * x + qy * z - qz * y; + var iy = qw * y + qz * x - qx * z; + var iz = qw * z + qx * y - qy * x; + var iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + + this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + + return this; + + }, + + transformDirection: function ( m ) { + + // input: THREE.Matrix4 affine matrix + // vector interpreted as a direction + + var x = this.x, y = this.y, z = this.z; + + var e = m.elements; + + this.x = e[0] * x + e[4] * y + e[8] * z; + this.y = e[1] * x + e[5] * y + e[9] * z; + this.z = e[2] * x + e[6] * y + e[10] * z; + + this.normalize(); + + return this; + + }, + + divide: function ( v ) { + + this.x /= v.x; + this.y /= v.y; + this.z /= v.z; + + return this; + + }, + + divideScalar: function ( scalar ) { + + if ( scalar !== 0 ) { + + var invScalar = 1 / scalar; + + this.x *= invScalar; + this.y *= invScalar; + this.z *= invScalar; + + } else { + + this.x = 0; + this.y = 0; + this.z = 0; + + } + + return this; + + }, + + min: function ( v ) { + + if ( this.x > v.x ) { + + this.x = v.x; + + } + + if ( this.y > v.y ) { + + this.y = v.y; + + } + + if ( this.z > v.z ) { + + this.z = v.z; + + } + + return this; + + }, + + max: function ( v ) { + + if ( this.x < v.x ) { + + this.x = v.x; + + } + + if ( this.y < v.y ) { + + this.y = v.y; + + } + + if ( this.z < v.z ) { + + this.z = v.z; + + } + + return this; + + }, + + clamp: function ( min, max ) { + + // This function assumes min < max, if this assumption isn't true it will not operate correctly + + if ( this.x < min.x ) { + + this.x = min.x; + + } else if ( this.x > max.x ) { + + this.x = max.x; + + } + + if ( this.y < min.y ) { + + this.y = min.y; + + } else if ( this.y > max.y ) { + + this.y = max.y; + + } + + if ( this.z < min.z ) { + + this.z = min.z; + + } else if ( this.z > max.z ) { + + this.z = max.z; + + } + + return this; + + }, + + clampScalar: ( function () { + + var min, max; + + return function ( minVal, maxVal ) { + + if ( min === undefined ) { + + min = new THREE.Vector3(); + max = new THREE.Vector3(); + + } + + min.set( minVal, minVal, minVal ); + max.set( maxVal, maxVal, maxVal ); + + return this.clamp( min, max ); + + }; + + } )(), + + floor: function () { + + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + + return this; + + }, + + ceil: function () { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + + return this; + + }, + + round: function () { + + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + + return this; + + }, + + roundToZero: function () { + + this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); + this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); + + return this; + + }, + + negate: function () { + + return this.multiplyScalar( - 1 ); + + }, + + dot: function ( v ) { + + return this.x * v.x + this.y * v.y + this.z * v.z; + + }, + + lengthSq: function () { + + return this.x * this.x + this.y * this.y + this.z * this.z; + + }, + + length: function () { + + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); + + }, + + lengthManhattan: function () { + + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); + + }, + + normalize: function () { + + return this.divideScalar( this.length() ); + + }, + + setLength: function ( l ) { + + var oldLength = this.length(); + + if ( oldLength !== 0 && l !== oldLength ) { + + this.multiplyScalar( l / oldLength ); + } + + return this; + + }, + + lerp: function ( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + + return this; + + }, + + cross: function ( v, w ) { + + if ( w !== undefined ) { + + THREE.onwarning( 'DEPRECATED: Vector3\'s .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); + return this.crossVectors( v, w ); + + } + + var x = this.x, y = this.y, z = this.z; + + this.x = y * v.z - z * v.y; + this.y = z * v.x - x * v.z; + this.z = x * v.y - y * v.x; + + return this; + + }, + + crossVectors: function ( a, b ) { + + var ax = a.x, ay = a.y, az = a.z; + var bx = b.x, by = b.y, bz = b.z; + + this.x = ay * bz - az * by; + this.y = az * bx - ax * bz; + this.z = ax * by - ay * bx; + + return this; + + }, + + projectOnVector: function () { + + var v1, dot; + + return function ( vector ) { + + if ( v1 === undefined ) v1 = new THREE.Vector3(); + + v1.copy( vector ).normalize(); + + dot = this.dot( v1 ); + + return this.copy( v1 ).multiplyScalar( dot ); + + }; + + }(), + + projectOnPlane: function () { + + var v1; + + return function ( planeNormal ) { + + if ( v1 === undefined ) v1 = new THREE.Vector3(); + + v1.copy( this ).projectOnVector( planeNormal ); + + return this.sub( v1 ); + + } + + }(), + + reflect: function () { + + // reflect incident vector off plane orthogonal to normal + // normal is assumed to have unit length + + var v1; + + return function ( normal ) { + + if ( v1 === undefined ) v1 = new THREE.Vector3(); + + return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); + + } + + }(), + + angleTo: function ( v ) { + + var theta = this.dot( v ) / ( this.length() * v.length() ); + + // clamp, to handle numerical problems + + return Math.acos( THREE.Math.clamp( theta, -1, 1 ) ); + + }, + + distanceTo: function ( v ) { + + return Math.sqrt( this.distanceToSquared( v ) ); + + }, + + distanceToSquared: function ( v ) { + + var dx = this.x - v.x; + var dy = this.y - v.y; + var dz = this.z - v.z; + + return dx * dx + dy * dy + dz * dz; + + }, + + setEulerFromRotationMatrix: function ( m, order ) { + + THREE.onerror( "REMOVED: Vector3\'s setEulerFromRotationMatrix has been removed in favor of Euler.setFromRotationMatrix(), please update your code."); + + }, + + setEulerFromQuaternion: function ( q, order ) { + + THREE.onerror( "REMOVED: Vector3\'s setEulerFromQuaternion: has been removed in favor of Euler.setFromQuaternion(), please update your code."); + + }, + + getPositionFromMatrix: function ( m ) { + + THREE.onwarning( "DEPRECATED: Vector3\'s .getPositionFromMatrix() has been renamed to .setFromMatrixPosition(). Please update your code." ); + + return this.setFromMatrixPosition( m ); + + }, + + getScaleFromMatrix: function ( m ) { + + THREE.onwarning( "DEPRECATED: Vector3\'s .getScaleFromMatrix() has been renamed to .setFromMatrixScale(). Please update your code." ); + + return this.setFromMatrixScale( m ); + }, + + getColumnFromMatrix: function ( index, matrix ) { + + THREE.onwarning( "DEPRECATED: Vector3\'s .getColumnFromMatrix() has been renamed to .setFromMatrixColumn(). Please update your code." ); + + return this.setFromMatrixColumn( index, matrix ); + + }, + + setFromMatrixPosition: function ( m ) { + + this.x = m.elements[ 12 ]; + this.y = m.elements[ 13 ]; + this.z = m.elements[ 14 ]; + + return this; + + }, + + setFromMatrixScale: function ( m ) { + + var sx = this.set( m.elements[ 0 ], m.elements[ 1 ], m.elements[ 2 ] ).length(); + var sy = this.set( m.elements[ 4 ], m.elements[ 5 ], m.elements[ 6 ] ).length(); + var sz = this.set( m.elements[ 8 ], m.elements[ 9 ], m.elements[ 10 ] ).length(); + + this.x = sx; + this.y = sy; + this.z = sz; + + return this; + }, + + setFromMatrixColumn: function ( index, matrix ) { + + var offset = index * 4; + + var me = matrix.elements; + + this.x = me[ offset ]; + this.y = me[ offset + 1 ]; + this.z = me[ offset + 2 ]; + + return this; + + }, + + equals: function ( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + + }, + + fromArray: function ( array ) { + + this.x = array[ 0 ]; + this.y = array[ 1 ]; + this.z = array[ 2 ]; + + return this; + + }, + + toArray: function () { + + return [ this.x, this.y, this.z ]; + + }, + + clone: function () { + + return new THREE.Vector3( this.x, this.y, this.z ); + + } + +}; +/** + * @author supereggbert / http://www.paulbrunt.co.uk/ + * @author philogb / http://blog.thejit.org/ + * @author mikael emtinger / http://gomo.se/ + * @author egraether / http://egraether.com/ + * @author WestLangley / http://github.com/WestLangley + */ + +THREE.Vector4 = function ( x, y, z, w ) { + + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + this.w = ( w !== undefined ) ? w : 1; + +}; + +THREE.Vector4.prototype = { + + constructor: THREE.Vector4, + + set: function ( x, y, z, w ) { + + this.x = x; + this.y = y; + this.z = z; + this.w = w; + + return this; + + }, + + setX: function ( x ) { + + this.x = x; + + return this; + + }, + + setY: function ( y ) { + + this.y = y; + + return this; + + }, + + setZ: function ( z ) { + + this.z = z; + + return this; + + }, + + setW: function ( w ) { + + this.w = w; + + return this; + + }, + + setComponent: function ( index, value ) { + + switch ( index ) { + + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + case 3: this.w = value; break; + default: return THREE.onerror( 'index is out of range: ' + index ); + + } + + }, + + getComponent: function ( index ) { + + switch ( index ) { + + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + case 3: return this.w; + default: return THREE.onerror( 'index is out of range: ' + index ); + + } + + }, + + copy: function ( v ) { + + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.w = ( v.w !== undefined ) ? v.w : 1; + + return this; + + }, + + add: function ( v, w ) { + + if ( w !== undefined ) { + + THREE.onwarning( 'DEPRECATED: Vector4\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); + + } + + this.x += v.x; + this.y += v.y; + this.z += v.z; + this.w += v.w; + + return this; + + }, + + addScalar: function ( s ) { + + this.x += s; + this.y += s; + this.z += s; + this.w += s; + + return this; + + }, + + addVectors: function ( a, b ) { + + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + this.w = a.w + b.w; + + return this; + + }, + + sub: function ( v, w ) { + + if ( w !== undefined ) { + + THREE.onwarning( 'DEPRECATED: Vector4\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); + + } + + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + this.w -= v.w; + + return this; + + }, + + subVectors: function ( a, b ) { + + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + this.w = a.w - b.w; + + return this; + + }, + + multiplyScalar: function ( scalar ) { + + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + this.w *= scalar; + + return this; + + }, + + applyMatrix4: function ( m ) { + + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); + + var x = this.x; + var y = this.y; + var z = this.z; + var w = this.w; + + var e = m.elements; + + this.x = e[0] * x + e[4] * y + e[8] * z + e[12] * w; + this.y = e[1] * x + e[5] * y + e[9] * z + e[13] * w; + this.z = e[2] * x + e[6] * y + e[10] * z + e[14] * w; + this.w = e[3] * x + e[7] * y + e[11] * z + e[15] * w; + + return this; + + }, + + divideScalar: function ( scalar ) { + + if ( scalar !== 0 ) { + + var invScalar = 1 / scalar; + + this.x *= invScalar; + this.y *= invScalar; + this.z *= invScalar; + this.w *= invScalar; + + } else { + + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 1; + + } + + return this; + + }, + + setAxisAngleFromQuaternion: function ( q ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm + + // q is assumed to be normalized + + this.w = 2 * Math.acos( q.w ); + + var s = Math.sqrt( 1 - q.w * q.w ); + + if ( s < 0.0001 ) { + + this.x = 1; + this.y = 0; + this.z = 0; + + } else { + + this.x = q.x / s; + this.y = q.y / s; + this.z = q.z / s; + + } + + return this; + + }, + + setAxisAngleFromRotationMatrix: function ( m ) { + + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + var angle, x, y, z, // variables for result + epsilon = 0.01, // margin to allow for rounding errors + epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees + + te = m.elements, + + m11 = te[0], m12 = te[4], m13 = te[8], + m21 = te[1], m22 = te[5], m23 = te[9], + m31 = te[2], m32 = te[6], m33 = te[10]; + + if ( ( Math.abs( m12 - m21 ) < epsilon ) + && ( Math.abs( m13 - m31 ) < epsilon ) + && ( Math.abs( m23 - m32 ) < epsilon ) ) { + + // singularity found + // first check for identity matrix which must have +1 for all terms + // in leading diagonal and zero in other terms + + if ( ( Math.abs( m12 + m21 ) < epsilon2 ) + && ( Math.abs( m13 + m31 ) < epsilon2 ) + && ( Math.abs( m23 + m32 ) < epsilon2 ) + && ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { + + // this singularity is identity matrix so angle = 0 + + this.set( 1, 0, 0, 0 ); + + return this; // zero angle, arbitrary axis + + } + + // otherwise this singularity is angle = 180 + + angle = Math.PI; + + var xx = ( m11 + 1 ) / 2; + var yy = ( m22 + 1 ) / 2; + var zz = ( m33 + 1 ) / 2; + var xy = ( m12 + m21 ) / 4; + var xz = ( m13 + m31 ) / 4; + var yz = ( m23 + m32 ) / 4; + + if ( ( xx > yy ) && ( xx > zz ) ) { // m11 is the largest diagonal term + + if ( xx < epsilon ) { + + x = 0; + y = 0.707106781; + z = 0.707106781; + + } else { + + x = Math.sqrt( xx ); + y = xy / x; + z = xz / x; + + } + + } else if ( yy > zz ) { // m22 is the largest diagonal term + + if ( yy < epsilon ) { + + x = 0.707106781; + y = 0; + z = 0.707106781; + + } else { + + y = Math.sqrt( yy ); + x = xy / y; + z = yz / y; + + } + + } else { // m33 is the largest diagonal term so base result on this + + if ( zz < epsilon ) { + + x = 0.707106781; + y = 0.707106781; + z = 0; + + } else { + + z = Math.sqrt( zz ); + x = xz / z; + y = yz / z; + + } + + } + + this.set( x, y, z, angle ); + + return this; // return 180 deg rotation + + } + + // as we have reached here there are no singularities so we can handle normally + + var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + + ( m13 - m31 ) * ( m13 - m31 ) + + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize + + if ( Math.abs( s ) < 0.001 ) s = 1; + + // prevent divide by zero, should not happen if matrix is orthogonal and should be + // caught by singularity test above, but I've left it in just in case + + this.x = ( m32 - m23 ) / s; + this.y = ( m13 - m31 ) / s; + this.z = ( m21 - m12 ) / s; + this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); + + return this; + + }, + + min: function ( v ) { + + if ( this.x > v.x ) { + + this.x = v.x; + + } + + if ( this.y > v.y ) { + + this.y = v.y; + + } + + if ( this.z > v.z ) { + + this.z = v.z; + + } + + if ( this.w > v.w ) { + + this.w = v.w; + + } + + return this; + + }, + + max: function ( v ) { + + if ( this.x < v.x ) { + + this.x = v.x; + + } + + if ( this.y < v.y ) { + + this.y = v.y; + + } + + if ( this.z < v.z ) { + + this.z = v.z; + + } + + if ( this.w < v.w ) { + + this.w = v.w; + + } + + return this; + + }, + + clamp: function ( min, max ) { + + // This function assumes min < max, if this assumption isn't true it will not operate correctly + + if ( this.x < min.x ) { + + this.x = min.x; + + } else if ( this.x > max.x ) { + + this.x = max.x; + + } + + if ( this.y < min.y ) { + + this.y = min.y; + + } else if ( this.y > max.y ) { + + this.y = max.y; + + } + + if ( this.z < min.z ) { + + this.z = min.z; + + } else if ( this.z > max.z ) { + + this.z = max.z; + + } + + if ( this.w < min.w ) { + + this.w = min.w; + + } else if ( this.w > max.w ) { + + this.w = max.w; + + } + + return this; + + }, + + clampScalar: ( function () { + + var min, max; + + return function ( minVal, maxVal ) { + + if ( min === undefined ) { + + min = new THREE.Vector4(); + max = new THREE.Vector4(); + + } + + min.set( minVal, minVal, minVal, minVal ); + max.set( maxVal, maxVal, maxVal, maxVal ); + + return this.clamp( min, max ); + + }; + + } )(), + + floor: function () { + + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + this.w = Math.floor( this.w ); + + return this; + + }, + + ceil: function () { + + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + this.w = Math.ceil( this.w ); + + return this; + + }, + + round: function () { + + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + this.w = Math.round( this.w ); + + return this; + + }, + + roundToZero: function () { + + this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); + this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); + this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w ); + + return this; + + }, + + negate: function () { + + return this.multiplyScalar( -1 ); + + }, + + dot: function ( v ) { + + return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; + + }, + + lengthSq: function () { + + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + + }, + + length: function () { + + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); + + }, + + lengthManhattan: function () { + + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); + + }, + + normalize: function () { + + return this.divideScalar( this.length() ); + + }, + + setLength: function ( l ) { + + var oldLength = this.length(); + + if ( oldLength !== 0 && l !== oldLength ) { + + this.multiplyScalar( l / oldLength ); + + } + + return this; + + }, + + lerp: function ( v, alpha ) { + + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + this.w += ( v.w - this.w ) * alpha; + + return this; + + }, + + equals: function ( v ) { + + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); + + }, + + fromArray: function ( array ) { + + this.x = array[ 0 ]; + this.y = array[ 1 ]; + this.z = array[ 2 ]; + this.w = array[ 3 ]; + + return this; + + }, + + toArray: function () { + + return [ this.x, this.y, this.z, this.w ]; + + }, + + clone: function () { + + return new THREE.Vector4( this.x, this.y, this.z, this.w ); + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://exocortex.com + */ + +THREE.Euler = function ( x, y, z, order ) { + + this._x = x || 0; + this._y = y || 0; + this._z = z || 0; + this._order = order || THREE.Euler.DefaultOrder; + +}; + +THREE.Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; + +THREE.Euler.DefaultOrder = 'XYZ'; + +THREE.Euler.prototype = { + + constructor: THREE.Euler, + + _x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder, + + _quaternion: undefined, + + _updateQuaternion: function () { + + if ( this._quaternion !== undefined ) { + + this._quaternion.setFromEuler( this, false ); + + } + + }, + + get x () { + + return this._x; + + }, + + set x ( value ) { + + this._x = value; + this._updateQuaternion(); + + }, + + get y () { + + return this._y; + + }, + + set y ( value ) { + + this._y = value; + this._updateQuaternion(); + + }, + + get z () { + + return this._z; + + }, + + set z ( value ) { + + this._z = value; + this._updateQuaternion(); + + }, + + get order () { + + return this._order; + + }, + + set order ( value ) { + + this._order = value; + this._updateQuaternion(); + + }, + + set: function ( x, y, z, order ) { + + this._x = x; + this._y = y; + this._z = z; + this._order = order || this._order; + + this._updateQuaternion(); + + return this; + + }, + + setFromVector: function ( v, order ) { + + this._x = v.x; + this._y = v.y; + this._z = v.z; + this._order = order || this._order; + + this._updateQuaternion(); + + return this; + + }, + + copy: function ( euler ) { + + this._x = euler._x; + this._y = euler._y; + this._z = euler._z; + this._order = euler._order; + + this._updateQuaternion(); + + return this; + + }, + + setFromRotationMatrix: function ( m, order, update ) { + + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + // clamp, to handle numerical problems + + function clamp( x ) { + + return Math.min( Math.max( x, -1 ), 1 ); + + } + + var te = m.elements; + var m11 = te[0], m12 = te[4], m13 = te[8]; + var m21 = te[1], m22 = te[5], m23 = te[9]; + var m31 = te[2], m32 = te[6], m33 = te[10]; + + order = order || this._order; + + if ( order === 'XYZ' ) { + + this._y = Math.asin( clamp( m13 ) ); + + if ( Math.abs( m13 ) < 0.99999 ) { + + this._x = Math.atan2( - m23, m33 ); + this._z = Math.atan2( - m12, m11 ); + + } else { + + this._x = Math.atan2( m32, m22 ); + this._z = 0; + + } + + } else if ( order === 'YXZ' ) { + + this._x = Math.asin( - clamp( m23 ) ); + + if ( Math.abs( m23 ) < 0.99999 ) { + + this._y = Math.atan2( m13, m33 ); + this._z = Math.atan2( m21, m22 ); + + } else { + + this._y = Math.atan2( - m31, m11 ); + this._z = 0; + + } + + } else if ( order === 'ZXY' ) { + + this._x = Math.asin( clamp( m32 ) ); + + if ( Math.abs( m32 ) < 0.99999 ) { + + this._y = Math.atan2( - m31, m33 ); + this._z = Math.atan2( - m12, m22 ); + + } else { + + this._y = 0; + this._z = Math.atan2( m21, m11 ); + + } + + } else if ( order === 'ZYX' ) { + + this._y = Math.asin( - clamp( m31 ) ); + + if ( Math.abs( m31 ) < 0.99999 ) { + + this._x = Math.atan2( m32, m33 ); + this._z = Math.atan2( m21, m11 ); + + } else { + + this._x = 0; + this._z = Math.atan2( - m12, m22 ); + + } + + } else if ( order === 'YZX' ) { + + this._z = Math.asin( clamp( m21 ) ); + + if ( Math.abs( m21 ) < 0.99999 ) { + + this._x = Math.atan2( - m23, m22 ); + this._y = Math.atan2( - m31, m11 ); + + } else { + + this._x = 0; + this._y = Math.atan2( m13, m33 ); + + } + + } else if ( order === 'XZY' ) { + + this._z = Math.asin( - clamp( m12 ) ); + + if ( Math.abs( m12 ) < 0.99999 ) { + + this._x = Math.atan2( m32, m22 ); + this._y = Math.atan2( m13, m11 ); + + } else { + + this._x = Math.atan2( - m23, m33 ); + this._y = 0; + + } + + } else { + + THREE.onwarning( 'WARNING: Euler.setFromRotationMatrix() given unsupported order: ' + order ) + + } + + this._order = order; + + if ( update !== false ) this._updateQuaternion(); + + return this; + + }, + + setFromQuaternion: function() { + + var mIntermediate = null; + + return function( q, order, update ) { + + mIntermediate = mIntermediate || new THREE.Matrix4(); + mIntermediate.makeRotationFromQuaternion( q ); + this.setFromRotationMatrix( mIntermediate, order, update ); + + return this; + }; + + }(), + + reorder: function () { + + // WARNING: this discards revolution information -bhouston + + var q = new THREE.Quaternion(); + + return function ( newOrder ) { + + q.setFromEuler( this ); + this.setFromQuaternion( q, newOrder ); + + }; + + + }(), + + fromArray: function ( array ) { + + this._x = array[ 0 ]; + this._y = array[ 1 ]; + this._z = array[ 2 ]; + if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; + + this._updateQuaternion(); + + return this; + + }, + + toArray: function () { + + return [ this._x, this._y, this._z, this._order ]; + + }, + + equals: function ( euler ) { + + return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + + }, + + + toVector3: function ( optionalResult ) { + + if( optionalResult ) { + return optionalResult.set( this._x, this._y, this._z ); + } + else { + return new THREE.Vector3( this._x, this._y, this._z ); + } + + }, + + clone: function () { + + return new THREE.Euler( this._x, this._y, this._z, this._order ); + + } + +}; + +/** + * @author bhouston / http://exocortex.com + */ + +THREE.Line3 = function ( start, end ) { + + this.start = ( start !== undefined ) ? start : new THREE.Vector3(); + this.end = ( end !== undefined ) ? end : new THREE.Vector3(); + +}; + +THREE.Line3.prototype = { + + constructor: THREE.Line3, + + set: function ( start, end ) { + + this.start.copy( start ); + this.end.copy( end ); + + return this; + + }, + + copy: function ( line ) { + + this.start.copy( line.start ); + this.end.copy( line.end ); + + return this; + + }, + + center: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); + + }, + + delta: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.subVectors( this.end, this.start ); + + }, + + distanceSq: function () { + + return this.start.distanceToSquared( this.end ); + + }, + + distance: function () { + + return this.start.distanceTo( this.end ); + + }, + + at: function ( t, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + + return this.delta( result ).multiplyScalar( t ).add( this.start ); + + }, + + closestPointToPointParameter: function() { + + var startP = new THREE.Vector3(); + var startEnd = new THREE.Vector3(); + + return function ( point, clampToLine ) { + + startP.subVectors( point, this.start ); + startEnd.subVectors( this.end, this.start ); + + var startEnd2 = startEnd.dot( startEnd ); + var startEnd_startP = startEnd.dot( startP ); + + var t = startEnd_startP / startEnd2; + + if ( clampToLine ) { + + t = THREE.Math.clamp( t, 0, 1 ); + + } + + return t; + + }; + + }(), + + closestPointToPoint: function ( point, clampToLine, optionalTarget ) { + + var t = this.closestPointToPointParameter( point, clampToLine ); + + var result = optionalTarget || new THREE.Vector3(); + + return this.delta( result ).multiplyScalar( t ).add( this.start ); + + }, + + applyMatrix4: function ( matrix ) { + + this.start.applyMatrix4( matrix ); + this.end.applyMatrix4( matrix ); + + return this; + + }, + + equals: function ( line ) { + + return line.start.equals( this.start ) && line.end.equals( this.end ); + + }, + + clone: function () { + + return new THREE.Line3().copy( this ); + + } + +}; + +/** + * @author bhouston / http://exocortex.com + */ + +THREE.Box2 = function ( min, max ) { + + this.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity ); + this.max = ( max !== undefined ) ? max : new THREE.Vector2( -Infinity, -Infinity ); + +}; + +THREE.Box2.prototype = { + + constructor: THREE.Box2, + + set: function ( min, max ) { + + this.min.copy( min ); + this.max.copy( max ); + + return this; + + }, + + setFromPoints: function ( points ) { + + if ( points.length > 0 ) { + + var point = points[ 0 ]; + + this.min.copy( point ); + this.max.copy( point ); + + for ( var i = 1, il = points.length; i < il; i ++ ) { + + point = points[ i ]; + + if ( point.x < this.min.x ) { + + this.min.x = point.x; + + } else if ( point.x > this.max.x ) { + + this.max.x = point.x; + + } + + if ( point.y < this.min.y ) { + + this.min.y = point.y; + + } else if ( point.y > this.max.y ) { + + this.max.y = point.y; + + } + + } + + } else { + + this.makeEmpty(); + + } + + return this; + + }, + + setFromCenterAndSize: function () { + + var v1 = new THREE.Vector2(); + + return function ( center, size ) { + + var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); + + return this; + + }; + + }(), + + copy: function ( box ) { + + this.min.copy( box.min ); + this.max.copy( box.max ); + + return this; + + }, + + makeEmpty: function () { + + this.min.x = this.min.y = Infinity; + this.max.x = this.max.y = -Infinity; + + return this; + + }, + + empty: function () { + + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); + + }, + + center: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector2(); + return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + + }, + + size: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector2(); + return result.subVectors( this.max, this.min ); + + }, + + expandByPoint: function ( point ) { + + this.min.min( point ); + this.max.max( point ); + + return this; + }, + + expandByVector: function ( vector ) { + + this.min.sub( vector ); + this.max.add( vector ); + + return this; + }, + + expandByScalar: function ( scalar ) { + + this.min.addScalar( -scalar ); + this.max.addScalar( scalar ); + + return this; + }, + + containsPoint: function ( point ) { + + if ( point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y ) { + + return false; + + } + + return true; + + }, + + containsBox: function ( box ) { + + if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && + ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) { + + return true; + + } + + return false; + + }, + + getParameter: function ( point, optionalTarget ) { + + // This can potentially have a divide by zero if the box + // has a size dimension of 0. + + var result = optionalTarget || new THREE.Vector2(); + + return result.set( + ( point.x - this.min.x ) / ( this.max.x - this.min.x ), + ( point.y - this.min.y ) / ( this.max.y - this.min.y ) + ); + + }, + + isIntersectionBox: function ( box ) { + + // using 6 splitting planes to rule out intersections. + + if ( box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y ) { + + return false; + + } + + return true; + + }, + + clampPoint: function ( point, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector2(); + return result.copy( point ).clamp( this.min, this.max ); + + }, + + distanceToPoint: function () { + + var v1 = new THREE.Vector2(); + + return function ( point ) { + + var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); + + }; + + }(), + + intersect: function ( box ) { + + this.min.max( box.min ); + this.max.min( box.max ); + + return this; + + }, + + union: function ( box ) { + + this.min.min( box.min ); + this.max.max( box.max ); + + return this; + + }, + + translate: function ( offset ) { + + this.min.add( offset ); + this.max.add( offset ); + + return this; + + }, + + equals: function ( box ) { + + return box.min.equals( this.min ) && box.max.equals( this.max ); + + }, + + clone: function () { + + return new THREE.Box2().copy( this ); + + } + +}; + +/** + * @author bhouston / http://exocortex.com + * @author WestLangley / http://github.com/WestLangley + */ + +THREE.Box3 = function ( min, max ) { + + this.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity ); + this.max = ( max !== undefined ) ? max : new THREE.Vector3( -Infinity, -Infinity, -Infinity ); + +}; + +THREE.Box3.prototype = { + + constructor: THREE.Box3, + + set: function ( min, max ) { + + this.min.copy( min ); + this.max.copy( max ); + + return this; + + }, + + addPoint: function ( point ) { + + if ( point.x < this.min.x ) { + + this.min.x = point.x; + + } else if ( point.x > this.max.x ) { + + this.max.x = point.x; + + } + + if ( point.y < this.min.y ) { + + this.min.y = point.y; + + } else if ( point.y > this.max.y ) { + + this.max.y = point.y; + + } + + if ( point.z < this.min.z ) { + + this.min.z = point.z; + + } else if ( point.z > this.max.z ) { + + this.max.z = point.z; + + } + + }, + + setFromPoints: function ( points ) { + + if ( points.length > 0 ) { + + var point = points[ 0 ]; + + this.min.copy( point ); + this.max.copy( point ); + + for ( var i = 1, il = points.length; i < il; i ++ ) { + + this.addPoint( points[ i ] ) + + } + + } else { + + this.makeEmpty(); + + } + + return this; + + }, + + setFromCenterAndSize: function() { + + var v1 = new THREE.Vector3(); + + return function ( center, size ) { + + var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); + + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); + + return this; + + }; + + }(), + + setFromObject: function() { + + // Computes the world-axis-aligned bounding box of an object (including its children), + // accounting for both the object's, and childrens', world transforms + + var v1 = new THREE.Vector3(); + + return function( object ) { + + var scope = this; + + object.updateMatrixWorld( true ); + + this.makeEmpty(); + + object.traverse( function ( node ) { + + if ( node.geometry !== undefined && node.geometry.vertices !== undefined ) { + + var vertices = node.geometry.vertices; + + for ( var i = 0, il = vertices.length; i < il; i++ ) { + + v1.copy( vertices[ i ] ); + + v1.applyMatrix4( node.matrixWorld ); + + scope.expandByPoint( v1 ); + + } + + } + + } ); + + return this; + + }; + + }(), + + copy: function ( box ) { + + this.min.copy( box.min ); + this.max.copy( box.max ); + + return this; + + }, + + makeEmpty: function () { + + this.min.x = this.min.y = this.min.z = Infinity; + this.max.x = this.max.y = this.max.z = -Infinity; + + return this; + + }, + + empty: function () { + + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); + + }, + + center: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + + }, + + size: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.subVectors( this.max, this.min ); + + }, + + expandByPoint: function ( point ) { + + this.min.min( point ); + this.max.max( point ); + + return this; + + }, + + expandByVector: function ( vector ) { + + this.min.sub( vector ); + this.max.add( vector ); + + return this; + + }, + + expandByScalar: function ( scalar ) { + + this.min.addScalar( -scalar ); + this.max.addScalar( scalar ); + + return this; + + }, + + containsPoint: function ( point ) { + + if ( point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y || + point.z < this.min.z || point.z > this.max.z ) { + + return false; + + } + + return true; + + }, + + containsBox: function ( box ) { + + if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && + ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) && + ( this.min.z <= box.min.z ) && ( box.max.z <= this.max.z ) ) { + + return true; + + } + + return false; + + }, + + getParameter: function ( point, optionalTarget ) { + + // This can potentially have a divide by zero if the box + // has a size dimension of 0. + + var result = optionalTarget || new THREE.Vector3(); + + return result.set( + ( point.x - this.min.x ) / ( this.max.x - this.min.x ), + ( point.y - this.min.y ) / ( this.max.y - this.min.y ), + ( point.z - this.min.z ) / ( this.max.z - this.min.z ) + ); + + }, + + isIntersectionBox: function ( box ) { + + // using 6 splitting planes to rule out intersections. + + if ( box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y || + box.max.z < this.min.z || box.min.z > this.max.z ) { + + return false; + + } + + return true; + + }, + + clampPoint: function ( point, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.copy( point ).clamp( this.min, this.max ); + + }, + + distanceToPoint: function() { + + var v1 = new THREE.Vector3(); + + return function ( point ) { + + var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); + + }; + + }(), + + getBoundingSphere: function() { + + var v1 = new THREE.Vector3(); + + return function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Sphere(); + + result.center = this.center(); + result.radius = this.size( v1 ).length() * 0.5; + + return result; + + }; + + }(), + + intersect: function ( box ) { + + this.min.max( box.min ); + this.max.min( box.max ); + + return this; + + }, + + union: function ( box ) { + + this.min.min( box.min ); + this.max.max( box.max ); + + return this; + + }, + + applyMatrix4: function() { + + var points = [ + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3(), + new THREE.Vector3() + ]; + + return function ( matrix ) { + + // NOTE: I am using a binary pattern to specify all 2^3 combinations below + points[0].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 + points[1].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 + points[2].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 + points[3].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 + points[4].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 + points[5].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 + points[6].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 + points[7].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 + + this.makeEmpty(); + this.setFromPoints( points ); + + return this; + + }; + + }(), + + translate: function ( offset ) { + + this.min.add( offset ); + this.max.add( offset ); + + return this; + + }, + + equals: function ( box ) { + + return box.min.equals( this.min ) && box.max.equals( this.max ); + + }, + + clone: function () { + + return new THREE.Box3().copy( this ); + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author bhouston / http://exocortex.com + */ + +THREE.Matrix3 = function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { + + this.elements = new Float32Array(9); + + this.set( + + ( n11 !== undefined ) ? n11 : 1, n12 || 0, n13 || 0, + n21 || 0, ( n22 !== undefined ) ? n22 : 1, n23 || 0, + n31 || 0, n32 || 0, ( n33 !== undefined ) ? n33 : 1 + + ); +}; + +THREE.Matrix3.prototype = { + + constructor: THREE.Matrix3, + + set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { + + var te = this.elements; + + te[0] = n11; te[3] = n12; te[6] = n13; + te[1] = n21; te[4] = n22; te[7] = n23; + te[2] = n31; te[5] = n32; te[8] = n33; + + return this; + + }, + + identity: function () { + + this.set( + + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + + ); + + return this; + + }, + + copy: function ( m ) { + + var me = m.elements; + + this.set( + + me[0], me[3], me[6], + me[1], me[4], me[7], + me[2], me[5], me[8] + + ); + + return this; + + }, + + multiplyVector3: function ( vector ) { + + THREE.onwarning( 'DEPRECATED: Matrix3\'s .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); + return vector.applyMatrix3( this ); + + }, + + multiplyVector3Array: function() { + + var v1 = new THREE.Vector3(); + + return function ( a ) { + + for ( var i = 0, il = a.length; i < il; i += 3 ) { + + v1.x = a[ i ]; + v1.y = a[ i + 1 ]; + v1.z = a[ i + 2 ]; + + v1.applyMatrix3(this); + + a[ i ] = v1.x; + a[ i + 1 ] = v1.y; + a[ i + 2 ] = v1.z; + + } + + return a; + + }; + + }(), + + multiplyScalar: function ( s ) { + + var te = this.elements; + + te[0] *= s; te[3] *= s; te[6] *= s; + te[1] *= s; te[4] *= s; te[7] *= s; + te[2] *= s; te[5] *= s; te[8] *= s; + + return this; + + }, + + determinant: function () { + + var te = this.elements; + + var a = te[0], b = te[1], c = te[2], + d = te[3], e = te[4], f = te[5], + g = te[6], h = te[7], i = te[8]; + + return a*e*i - a*f*h - b*d*i + b*f*g + c*d*h - c*e*g; + + }, + + getInverse: function ( matrix, errorOnInvertible ) { + + if ( ! ( matrix instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', matrix ); + // ( based on http://code.google.com/p/webgl-mjs/ ) + + var me = matrix.elements; + var te = this.elements; + + te[ 0 ] = me[10] * me[5] - me[6] * me[9]; + te[ 1 ] = - me[10] * me[1] + me[2] * me[9]; + te[ 2 ] = me[6] * me[1] - me[2] * me[5]; + te[ 3 ] = - me[10] * me[4] + me[6] * me[8]; + te[ 4 ] = me[10] * me[0] - me[2] * me[8]; + te[ 5 ] = - me[6] * me[0] + me[2] * me[4]; + te[ 6 ] = me[9] * me[4] - me[5] * me[8]; + te[ 7 ] = - me[9] * me[0] + me[1] * me[8]; + te[ 8 ] = me[5] * me[0] - me[1] * me[4]; + + var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ]; + + // no inverse + + if ( det === 0 ) { + + if ( errorOnInvertible === true ) { + + return THREE.onerror( "Matrix3.getInverse(): can't invert matrix, determinant is 0", this ); + + } + + this.identity(); + + return this; + + } + + this.multiplyScalar( 1.0 / det ); + + return this; + + }, + + transpose: function () { + + var tmp, m = this.elements; + + tmp = m[1]; m[1] = m[3]; m[3] = tmp; + tmp = m[2]; m[2] = m[6]; m[6] = tmp; + tmp = m[5]; m[5] = m[7]; m[7] = tmp; + + return this; + + }, + + getNormalMatrix: function ( m ) { + + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); + + this.getInverse( m ).transpose(); + + return this; + + }, + + transposeIntoArray: function ( r ) { + + var m = this.elements; + + r[ 0 ] = m[ 0 ]; + r[ 1 ] = m[ 3 ]; + r[ 2 ] = m[ 6 ]; + r[ 3 ] = m[ 1 ]; + r[ 4 ] = m[ 4 ]; + r[ 5 ] = m[ 7 ]; + r[ 6 ] = m[ 2 ]; + r[ 7 ] = m[ 5 ]; + r[ 8 ] = m[ 8 ]; + + return this; + + }, + + fromArray: function ( array ) { + + this.elements.set( array ); + + return this; + + }, + + toArray: function () { + + var te = this.elements; + + return [ + te[ 0 ], te[ 1 ], te[ 2 ], + te[ 3 ], te[ 4 ], te[ 5 ], + te[ 6 ], te[ 7 ], te[ 8 ] + ]; + + }, + + clone: function () { + + var te = this.elements; + + return new THREE.Matrix3( + + te[0], te[3], te[6], + te[1], te[4], te[7], + te[2], te[5], te[8] + + ); + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author supereggbert / http://www.paulbrunt.co.uk/ + * @author philogb / http://blog.thejit.org/ + * @author jordi_ros / http://plattsoft.com + * @author D1plo1d / http://github.com/D1plo1d + * @author alteredq / http://alteredqualia.com/ + * @author mikael emtinger / http://gomo.se/ + * @author timknip / http://www.floorplanner.com/ + * @author bhouston / http://exocortex.com + * @author WestLangley / http://github.com/WestLangley + */ + + +THREE.Matrix4 = function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + + this.elements = new Float32Array( 16 ); + + // TODO: if n11 is undefined, then just set to identity, otherwise copy all other values into matrix + // we should not support semi specification of Matrix4, it is just weird. + + var te = this.elements; + + te[0] = ( n11 !== undefined ) ? n11 : 1; te[4] = n12 || 0; te[8] = n13 || 0; te[12] = n14 || 0; + te[1] = n21 || 0; te[5] = ( n22 !== undefined ) ? n22 : 1; te[9] = n23 || 0; te[13] = n24 || 0; + te[2] = n31 || 0; te[6] = n32 || 0; te[10] = ( n33 !== undefined ) ? n33 : 1; te[14] = n34 || 0; + te[3] = n41 || 0; te[7] = n42 || 0; te[11] = n43 || 0; te[15] = ( n44 !== undefined ) ? n44 : 1; + +}; + +THREE.Matrix4.prototype = { + + constructor: THREE.Matrix4, + + set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + + var te = this.elements; + + te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14; + te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24; + te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34; + te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44; + + return this; + + }, + + identity: function () { + + this.set( + + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + copy: function ( m ) { + + this.elements.set( m.elements ); + + return this; + + }, + + extractPosition: function ( m ) { + + THREE.onwarning( 'DEPRECATED: Matrix4\'s .extractPosition() has been renamed to .copyPosition().' ); + return this.copyPosition( m ); + + }, + + copyPosition: function ( m ) { + + var te = this.elements; + var me = m.elements; + + te[12] = me[12]; + te[13] = me[13]; + te[14] = me[14]; + + return this; + + }, + + extractBasis: function ( xAxis, yAxis, zAxis ) { + + var te = this.elements; + + xAxis.set( te[0], te[1], te[2] ); + yAxis.set( te[4], te[5], te[6] ); + zAxis.set( te[8], te[9], te[10] ); + + return this; + + }, + + makeBasis: function ( xAxis, yAxis, zAxis ) { + + this.identity(); + + var te = this.elements; + te.elements[0] = xAxis.x; te.elements[1] = xAxis.y; te.elements[2] = xAxis.z; + te.elements[4] = yAxis.x; te.elements[5] = yAxis.y; te.elements[6] = yAxis.z; + te.elements[8] = zAxis.x; te.elements[9] = zAxis.y; te.elements[10] = zAxis.z; + + return this; + + }, + + extractRotation: function () { + + var v1 = new THREE.Vector3(); + + return function ( m ) { + + var te = this.elements; + var me = m.elements; + + var scaleX = 1 / v1.set( me[0], me[1], me[2] ).length(); + var scaleY = 1 / v1.set( me[4], me[5], me[6] ).length(); + var scaleZ = 1 / v1.set( me[8], me[9], me[10] ).length(); + + te[0] = me[0] * scaleX; + te[1] = me[1] * scaleX; + te[2] = me[2] * scaleX; + + te[4] = me[4] * scaleY; + te[5] = me[5] * scaleY; + te[6] = me[6] * scaleY; + + te[8] = me[8] * scaleZ; + te[9] = me[9] * scaleZ; + te[10] = me[10] * scaleZ; + + return this; + + }; + + }(), + + makeRotationFromEuler: function ( euler ) { + + if ( ! ( euler instanceof THREE.Euler ) ) return THREE.onerror( 'expecting a Euler', euler ); + + var te = this.elements; + + var x = euler.x, y = euler.y, z = euler.z; + var a = Math.cos( x ), b = Math.sin( x ); + var c = Math.cos( y ), d = Math.sin( y ); + var e = Math.cos( z ), f = Math.sin( z ); + + if ( euler.order === 'XYZ' ) { + + var ae = a * e, af = a * f, be = b * e, bf = b * f; + + te[0] = c * e; + te[4] = - c * f; + te[8] = d; + + te[1] = af + be * d; + te[5] = ae - bf * d; + te[9] = - b * c; + + te[2] = bf - ae * d; + te[6] = be + af * d; + te[10] = a * c; + + } else if ( euler.order === 'YXZ' ) { + + var ce = c * e, cf = c * f, de = d * e, df = d * f; + + te[0] = ce + df * b; + te[4] = de * b - cf; + te[8] = a * d; + + te[1] = a * f; + te[5] = a * e; + te[9] = - b; + + te[2] = cf * b - de; + te[6] = df + ce * b; + te[10] = a * c; + + } else if ( euler.order === 'ZXY' ) { + + var ce = c * e, cf = c * f, de = d * e, df = d * f; + + te[0] = ce - df * b; + te[4] = - a * f; + te[8] = de + cf * b; + + te[1] = cf + de * b; + te[5] = a * e; + te[9] = df - ce * b; + + te[2] = - a * d; + te[6] = b; + te[10] = a * c; + + } else if ( euler.order === 'ZYX' ) { + + var ae = a * e, af = a * f, be = b * e, bf = b * f; + + te[0] = c * e; + te[4] = be * d - af; + te[8] = ae * d + bf; + + te[1] = c * f; + te[5] = bf * d + ae; + te[9] = af * d - be; + + te[2] = - d; + te[6] = b * c; + te[10] = a * c; + + } else if ( euler.order === 'YZX' ) { + + var ac = a * c, ad = a * d, bc = b * c, bd = b * d; + + te[0] = c * e; + te[4] = bd - ac * f; + te[8] = bc * f + ad; + + te[1] = f; + te[5] = a * e; + te[9] = - b * e; + + te[2] = - d * e; + te[6] = ad * f + bc; + te[10] = ac - bd * f; + + } else if ( euler.order === 'XZY' ) { + + var ac = a * c, ad = a * d, bc = b * c, bd = b * d; + + te[0] = c * e; + te[4] = - f; + te[8] = d * e; + + te[1] = ac * f + bd; + te[5] = a * e; + te[9] = ad * f - bc; + + te[2] = bc * f - ad; + te[6] = b * e; + te[10] = bd * f + ac; + + } + + // last column + te[3] = 0; + te[7] = 0; + te[11] = 0; + + // bottom row + te[12] = 0; + te[13] = 0; + te[14] = 0; + te[15] = 1; + + return this; + + }, + + setRotationFromQuaternion: function ( q ) { + + THREE.onwarning( 'DEPRECATED: Matrix4\'s .setRotationFromQuaternion() has been deprecated in favor of makeRotationFromQuaternion. Please update your code.' ); + + return this.makeRotationFromQuaternion( q ); + + }, + + makeRotationFromQuaternion: function ( q ) { + + var te = this.elements; + + var x = q.x, y = q.y, z = q.z, w = q.w; + var x2 = x + x, y2 = y + y, z2 = z + z; + var xx = x * x2, xy = x * y2, xz = x * z2; + var yy = y * y2, yz = y * z2, zz = z * z2; + var wx = w * x2, wy = w * y2, wz = w * z2; + + te[0] = 1 - ( yy + zz ); + te[4] = xy - wz; + te[8] = xz + wy; + + te[1] = xy + wz; + te[5] = 1 - ( xx + zz ); + te[9] = yz - wx; + + te[2] = xz - wy; + te[6] = yz + wx; + te[10] = 1 - ( xx + yy ); + + // last column + te[3] = 0; + te[7] = 0; + te[11] = 0; + + // bottom row + te[12] = 0; + te[13] = 0; + te[14] = 0; + te[15] = 1; + + return this; + + }, + + lookAt: function() { + + var x = new THREE.Vector3(); + var y = new THREE.Vector3(); + var z = new THREE.Vector3(); + + return function ( eye, target, up ) { + + var te = this.elements; + + z.subVectors( eye, target ).normalize(); + + if ( z.length() === 0 ) { + + z.z = 1; + + } + + x.crossVectors( up, z ).normalize(); + + if ( x.length() === 0 ) { + + z.x += 0.0001; + x.crossVectors( up, z ).normalize(); + + } + + y.crossVectors( z, x ); + + + te[0] = x.x; te[4] = y.x; te[8] = z.x; + te[1] = x.y; te[5] = y.y; te[9] = z.y; + te[2] = x.z; te[6] = y.z; te[10] = z.z; + + return this; + + }; + + }(), + + multiply: function ( m, n ) { + + if ( n !== undefined ) { + + THREE.onwarning( 'DEPRECATED: Matrix4\'s .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); + return this.multiplyMatrices( m, n ); + + } + + return this.multiplyMatrices( this, m ); + + }, + + multiplyList: function ( listOfMatrices ) { + + for (var i = 0, il = listOfMatrices.length; i < il ; i++) { + this.multiplyMatrices( this, listOfMatrices[ i ] ); + } + + return this; + + }, + + multiplyMatricesList: function ( listOfMatrices ) { + + if( listOfMatrices.length > 0 ) { + + this.copy( listOfMatrices[0] ); + + this.multiplyList( listOfMatrices.slice( 1 ) ); + + } + else { + + this.identity(); + + } + + return this; + + }, + + multiplyMatrices: function ( a, b ) { + + if ( ! ( a instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', a ); + if ( ! ( b instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', b ); + + var ae = a.elements; + var be = b.elements; + var te = this.elements; + + var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12]; + var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13]; + var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14]; + var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15]; + + var b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12]; + var b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13]; + var b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14]; + var b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15]; + + te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; + te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; + te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; + te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; + + te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; + te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; + te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; + te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; + + te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; + te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; + te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; + te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; + + te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; + te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; + te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; + te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; + + return this; + + }, + + multiplyToArray: function ( a, b, r ) { + + var te = this.elements; + + this.multiplyMatrices( a, b ); + + r[ 0 ] = te[0]; r[ 1 ] = te[1]; r[ 2 ] = te[2]; r[ 3 ] = te[3]; + r[ 4 ] = te[4]; r[ 5 ] = te[5]; r[ 6 ] = te[6]; r[ 7 ] = te[7]; + r[ 8 ] = te[8]; r[ 9 ] = te[9]; r[ 10 ] = te[10]; r[ 11 ] = te[11]; + r[ 12 ] = te[12]; r[ 13 ] = te[13]; r[ 14 ] = te[14]; r[ 15 ] = te[15]; + + return this; + + }, + + multiplyScalar: function ( s ) { + + var te = this.elements; + + te[0] *= s; te[4] *= s; te[8] *= s; te[12] *= s; + te[1] *= s; te[5] *= s; te[9] *= s; te[13] *= s; + te[2] *= s; te[6] *= s; te[10] *= s; te[14] *= s; + te[3] *= s; te[7] *= s; te[11] *= s; te[15] *= s; + + return this; + + }, + + multiplyVector3: function ( vector ) { + + THREE.onwarning( 'DEPRECATED: Matrix4\'s .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); + return vector.applyProjection( this ); + + }, + + multiplyVector4: function ( vector ) { + + THREE.onwarning( 'DEPRECATED: Matrix4\'s .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); + + }, + + multiplyVector3Array: function() { + + var v1 = new THREE.Vector3(); + + return function ( a ) { + + for ( var i = 0, il = a.length; i < il; i += 3 ) { + + v1.x = a[ i ]; + v1.y = a[ i + 1 ]; + v1.z = a[ i + 2 ]; + + v1.applyProjection( this ); + + a[ i ] = v1.x; + a[ i + 1 ] = v1.y; + a[ i + 2 ] = v1.z; + + } + + return a; + + }; + + }(), + + rotateAxis: function ( v ) { + + THREE.onwarning( 'DEPRECATED: Matrix4\'s .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); + + v.transformDirection( this ); + + }, + + crossVector: function ( vector ) { + + THREE.onwarning( 'DEPRECATED: Matrix4\'s .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); + + }, + + determinant: function () { + + var te = this.elements; + + var n11 = te[0], n12 = te[4], n13 = te[8], n14 = te[12]; + var n21 = te[1], n22 = te[5], n23 = te[9], n24 = te[13]; + var n31 = te[2], n32 = te[6], n33 = te[10], n34 = te[14]; + var n41 = te[3], n42 = te[7], n43 = te[11], n44 = te[15]; + + //TODO: make this more efficient + //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) + + return ( + n41 * ( + +n14 * n23 * n32 + -n13 * n24 * n32 + -n14 * n22 * n33 + +n12 * n24 * n33 + +n13 * n22 * n34 + -n12 * n23 * n34 + ) + + n42 * ( + +n11 * n23 * n34 + -n11 * n24 * n33 + +n14 * n21 * n33 + -n13 * n21 * n34 + +n13 * n24 * n31 + -n14 * n23 * n31 + ) + + n43 * ( + +n11 * n24 * n32 + -n11 * n22 * n34 + -n14 * n21 * n32 + +n12 * n21 * n34 + +n14 * n22 * n31 + -n12 * n24 * n31 + ) + + n44 * ( + -n13 * n22 * n31 + -n11 * n23 * n32 + +n11 * n22 * n33 + +n13 * n21 * n32 + -n12 * n21 * n33 + +n12 * n23 * n31 + ) + + ); + + }, + + transpose: function () { + + var te = this.elements; + var tmp; + + tmp = te[1]; te[1] = te[4]; te[4] = tmp; + tmp = te[2]; te[2] = te[8]; te[8] = tmp; + tmp = te[6]; te[6] = te[9]; te[9] = tmp; + + tmp = te[3]; te[3] = te[12]; te[12] = tmp; + tmp = te[7]; te[7] = te[13]; te[13] = tmp; + tmp = te[11]; te[11] = te[14]; te[14] = tmp; + + return this; + + }, + + flattenToArray: function ( flat ) { + + var te = this.elements; + flat[ 0 ] = te[0]; flat[ 1 ] = te[1]; flat[ 2 ] = te[2]; flat[ 3 ] = te[3]; + flat[ 4 ] = te[4]; flat[ 5 ] = te[5]; flat[ 6 ] = te[6]; flat[ 7 ] = te[7]; + flat[ 8 ] = te[8]; flat[ 9 ] = te[9]; flat[ 10 ] = te[10]; flat[ 11 ] = te[11]; + flat[ 12 ] = te[12]; flat[ 13 ] = te[13]; flat[ 14 ] = te[14]; flat[ 15 ] = te[15]; + + return flat; + + }, + + flattenToArrayOffset: function( flat, offset ) { + + var te = this.elements; + flat[ offset ] = te[0]; + flat[ offset + 1 ] = te[1]; + flat[ offset + 2 ] = te[2]; + flat[ offset + 3 ] = te[3]; + + flat[ offset + 4 ] = te[4]; + flat[ offset + 5 ] = te[5]; + flat[ offset + 6 ] = te[6]; + flat[ offset + 7 ] = te[7]; + + flat[ offset + 8 ] = te[8]; + flat[ offset + 9 ] = te[9]; + flat[ offset + 10 ] = te[10]; + flat[ offset + 11 ] = te[11]; + + flat[ offset + 12 ] = te[12]; + flat[ offset + 13 ] = te[13]; + flat[ offset + 14 ] = te[14]; + flat[ offset + 15 ] = te[15]; + + return flat; + + }, + + getPosition: function() { + + var v1 = new THREE.Vector3(); + + return function () { + + THREE.onwarning( 'DEPRECATED: Matrix4\'s .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); + + var te = this.elements; + return v1.set( te[12], te[13], te[14] ); + + }; + + }(), + + setPosition: function ( v ) { + + var te = this.elements; + + te[12] = v.x; + te[13] = v.y; + te[14] = v.z; + + return this; + + }, + + getInverse: function ( m, errorOnInvertible ) { + + //if ( ! ( m instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', m ); + + // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm + var te = this.elements; + var me = m.elements; + + var n11 = me[0], n12 = me[4], n13 = me[8], n14 = me[12]; + var n21 = me[1], n22 = me[5], n23 = me[9], n24 = me[13]; + var n31 = me[2], n32 = me[6], n33 = me[10], n34 = me[14]; + var n41 = me[3], n42 = me[7], n43 = me[11], n44 = me[15]; + + te[0] = n23*n34*n42 - n24*n33*n42 + n24*n32*n43 - n22*n34*n43 - n23*n32*n44 + n22*n33*n44; + te[4] = n14*n33*n42 - n13*n34*n42 - n14*n32*n43 + n12*n34*n43 + n13*n32*n44 - n12*n33*n44; + te[8] = n13*n24*n42 - n14*n23*n42 + n14*n22*n43 - n12*n24*n43 - n13*n22*n44 + n12*n23*n44; + te[12] = n14*n23*n32 - n13*n24*n32 - n14*n22*n33 + n12*n24*n33 + n13*n22*n34 - n12*n23*n34; + te[1] = n24*n33*n41 - n23*n34*n41 - n24*n31*n43 + n21*n34*n43 + n23*n31*n44 - n21*n33*n44; + te[5] = n13*n34*n41 - n14*n33*n41 + n14*n31*n43 - n11*n34*n43 - n13*n31*n44 + n11*n33*n44; + te[9] = n14*n23*n41 - n13*n24*n41 - n14*n21*n43 + n11*n24*n43 + n13*n21*n44 - n11*n23*n44; + te[13] = n13*n24*n31 - n14*n23*n31 + n14*n21*n33 - n11*n24*n33 - n13*n21*n34 + n11*n23*n34; + te[2] = n22*n34*n41 - n24*n32*n41 + n24*n31*n42 - n21*n34*n42 - n22*n31*n44 + n21*n32*n44; + te[6] = n14*n32*n41 - n12*n34*n41 - n14*n31*n42 + n11*n34*n42 + n12*n31*n44 - n11*n32*n44; + te[10] = n12*n24*n41 - n14*n22*n41 + n14*n21*n42 - n11*n24*n42 - n12*n21*n44 + n11*n22*n44; + te[14] = n14*n22*n31 - n12*n24*n31 - n14*n21*n32 + n11*n24*n32 + n12*n21*n34 - n11*n22*n34; + te[3] = n23*n32*n41 - n22*n33*n41 - n23*n31*n42 + n21*n33*n42 + n22*n31*n43 - n21*n32*n43; + te[7] = n12*n33*n41 - n13*n32*n41 + n13*n31*n42 - n11*n33*n42 - n12*n31*n43 + n11*n32*n43; + te[11] = n13*n22*n41 - n12*n23*n41 - n13*n21*n42 + n11*n23*n42 + n12*n21*n43 - n11*n22*n43; + te[15] = n12*n23*n31 - n13*n22*n31 + n13*n21*n32 - n11*n23*n32 - n12*n21*n33 + n11*n22*n33; + + var det = n11 * te[ 0 ] + n21 * te[ 4 ] + n31 * te[ 8 ] + n41 * te[ 12 ]; + + if ( det == 0 ) { + + if ( errorOnInvertible === true ) { + + return THREE.onerror( "Matrix4.getInverse(): can't invert matrix, determinant is 0", this ); + + } + + this.identity(); + + return this; + } + + this.multiplyScalar( 1 / det ); + + return this; + + }, + + translate: function ( v ) { + + THREE.onerror( 'DEPRECATED: Matrix4\'s .translate() has been removed.'); + + }, + + rotateX: function ( angle ) { + + THREE.onerror( 'DEPRECATED: Matrix4\'s .rotateX() has been removed.'); + + }, + + rotateY: function ( angle ) { + + THREE.onerror( 'DEPRECATED: Matrix4\'s .rotateY() has been removed.'); + + }, + + rotateZ: function ( angle ) { + + THREE.onerror( 'DEPRECATED: Matrix4\'s .rotateZ() has been removed.'); + + }, + + rotateByAxis: function ( axis, angle ) { + + THREE.onerror( 'DEPRECATED: Matrix4\'s .rotateByAxis() has been removed.'); + + }, + + scale: function ( v ) { + + var te = this.elements; + var x = v.x, y = v.y, z = v.z; + + te[0] *= x; te[4] *= y; te[8] *= z; + te[1] *= x; te[5] *= y; te[9] *= z; + te[2] *= x; te[6] *= y; te[10] *= z; + te[3] *= x; te[7] *= y; te[11] *= z; + + return this; + + }, + + getMaxScaleOnAxis: function () { + + var te = this.elements; + + var scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2]; + var scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6]; + var scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10]; + + return Math.sqrt( Math.max( scaleXSq, Math.max( scaleYSq, scaleZSq ) ) ); + + }, + + makeTranslation: function ( x, y, z ) { + + this.set( + + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeRotationX: function ( theta ) { + + var c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + 1, 0, 0, 0, + 0, c, -s, 0, + 0, s, c, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeRotationY: function ( theta ) { + + var c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + c, 0, s, 0, + 0, 1, 0, 0, + -s, 0, c, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeRotationZ: function ( theta ) { + + var c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + c, -s, 0, 0, + s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeRotationAxis: function ( axis, angle ) { + + // Based on http://www.gamedev.net/reference/articles/article1199.asp + + var c = Math.cos( angle ); + var s = Math.sin( angle ); + var t = 1 - c; + var x = axis.x, y = axis.y, z = axis.z; + var tx = t * x, ty = t * y; + + this.set( + + tx * x + c, tx * y - s * z, tx * z + s * y, 0, + tx * y + s * z, ty * y + c, ty * z - s * x, 0, + tx * z - s * y, ty * z + s * x, t * z * z + c, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + makeScale: function ( x, y, z ) { + + this.set( + + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1 + + ); + + return this; + + }, + + + makeShear: function ( vector3Shear, reverseStyle ) { + + var xy = vector3Shear.x; + var xz = vector3Shear.y; + var yz = vector3Shear.z; + + if ( reverseStyle ) { + + this.set( + 1, 0, 0, 0, + xy, 1, 0, 0, + xz, yz, 1, 0, + 0, 0, 0, 1 + ); + + } else { + // Maya style + this.set( + 1, xy, xz, 0, + 0, 1, yz, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ); + } + + return this; + + }, + + compose: function ( position, quaternion, scale ) { + + this.makeRotationFromQuaternion( quaternion ); + this.scale( scale ); + this.setPosition( position ); + + return this; + + }, + + decompose: function () { + + var vector = new THREE.Vector3(); + var matrix = new THREE.Matrix4(); + + return function ( position, quaternion, scale ) { + + var te = this.elements; + + var sx = vector.set( te[0], te[1], te[2] ).length(); + var sy = vector.set( te[4], te[5], te[6] ).length(); + var sz = vector.set( te[8], te[9], te[10] ).length(); + + // if determine is negative, we need to invert one scale + var det = this.determinant(); + if( det < 0 ) { + sx = -sx; + } + + position.x = te[12]; + position.y = te[13]; + position.z = te[14]; + + // scale the rotation part + + matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy() + + var invSX = 1 / sx; + var invSY = 1 / sy; + var invSZ = 1 / sz; + + matrix.elements[0] *= invSX; + matrix.elements[1] *= invSX; + matrix.elements[2] *= invSX; + + matrix.elements[4] *= invSY; + matrix.elements[5] *= invSY; + matrix.elements[6] *= invSY; + + matrix.elements[8] *= invSZ; + matrix.elements[9] *= invSZ; + matrix.elements[10] *= invSZ; + + quaternion.setFromRotationMatrix( matrix ); + + scale.x = sx; + scale.y = sy; + scale.z = sz; + + return this; + + }; + + }(), + + makeFrustum: function ( left, right, bottom, top, near, far, filmOffset, filmSize ) { + + var te = this.elements; + var x = 2 * near / ( right - left ); + var y = 2 * near / ( top - bottom ); + + var a = ( right + left ) / ( right - left ); + var b = ( top + bottom ) / ( top - bottom ); + var c = - ( far + near ) / ( far - near ); + var d = - 2 * far * near / ( far - near ); + + te[0] = x; te[4] = 0; te[8] = a; te[12] = 0; + te[1] = 0; te[5] = y; te[9] = b; te[13] = 0; + te[2] = 0; te[6] = 0; te[10] = c; te[14] = d; + te[3] = 0; te[7] = 0; te[11] = - 1; te[15] = 0; + + if( filmOffset && filmSize ) { + // shift principle point, details: http://ksimek.github.io/2013/08/13/intrinsic/ + if( filmSize.x !== 0 ) { + te[8] += 2 * filmOffset.x / filmSize.x; + } + if( filmSize.y !== 0 ) { + te[9] += 2 * filmOffset.y / filmSize.y; + } + } + + return this; + + }, + + makePerspective: function ( fov, aspect, near, far, filmOffset, filmSize ) { + + var ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) ); + var ymin = - ymax; + var xmin = ymin * aspect; + var xmax = ymax * aspect; + + return this.makeFrustum( xmin, xmax, ymin, ymax, near, far, filmOffset, filmSize ); + + }, + + makeOrthographic: function ( left, right, top, bottom, near, far ) { + + var te = this.elements; + var w = right - left; + var h = top - bottom; + var p = far - near; + + var x = ( right + left ) / w; + var y = ( top + bottom ) / h; + var z = ( far + near ) / p; + + te[0] = 2 / w; te[4] = 0; te[8] = 0; te[12] = -x; + te[1] = 0; te[5] = 2 / h; te[9] = 0; te[13] = -y; + te[2] = 0; te[6] = 0; te[10] = -2/p; te[14] = -z; + te[3] = 0; te[7] = 0; te[11] = 0; te[15] = 1; + + return this; + + }, + + fromArray: function ( array ) { + + this.elements.set( array ); + + return this; + + }, + + toArray: function () { + + var te = this.elements; + + return [ + te[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ], + te[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ], + te[ 8 ], te[ 9 ], te[ 10 ], te[ 11 ], + te[ 12 ], te[ 13 ], te[ 14 ], te[ 15 ] + ]; + + }, + + clone: function () { + + var te = this.elements; + + return new THREE.Matrix4( + + te[0], te[4], te[8], te[12], + te[1], te[5], te[9], te[13], + te[2], te[6], te[10], te[14], + te[3], te[7], te[11], te[15] + + ); + + } + +}; + +/** + * @author bhouston / http://exocortex.com + */ + +THREE.Ray = function ( origin, direction ) { + + this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3(); + this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3(); + +}; + +THREE.Ray.prototype = { + + constructor: THREE.Ray, + + set: function ( origin, direction ) { + + this.origin.copy( origin ); + this.direction.copy( direction ); + + return this; + + }, + + copy: function ( ray ) { + + this.origin.copy( ray.origin ); + this.direction.copy( ray.direction ); + + return this; + + }, + + at: function ( t, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + + return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); + + }, + + recast: function () { + + var v1 = new THREE.Vector3(); + + return function ( t ) { + + this.origin.copy( this.at( t, v1 ) ); + + return this; + + }; + + }(), + + closestPointToPoint: function ( point, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + result.subVectors( point, this.origin ); + var directionDistance = result.dot( this.direction ); + + if ( directionDistance < 0 ) { + + return result.copy( this.origin ); + + } + + return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + + }, + + distanceToPoint: function () { + + var v1 = new THREE.Vector3(); + + return function ( point ) { + + var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); + + // point behind the ray + + if ( directionDistance < 0 ) { + + return this.origin.distanceTo( point ); + + } + + v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + + return v1.distanceTo( point ); + + }; + + }(), + + distanceSqToSegment: function( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { + + // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp + // It returns the min distance between the ray and the segment + // defined by v0 and v1 + // It can also set two optional targets : + // - The closest point on the ray + // - The closest point on the segment + + var segCenter = v0.clone().add( v1 ).multiplyScalar( 0.5 ); + var segDir = v1.clone().sub( v0 ).normalize(); + var segExtent = v0.distanceTo( v1 ) * 0.5; + var diff = this.origin.clone().sub( segCenter ); + var a01 = - this.direction.dot( segDir ); + var b0 = diff.dot( this.direction ); + var b1 = - diff.dot( segDir ); + var c = diff.lengthSq(); + var det = Math.abs( 1 - a01 * a01 ); + var s0, s1, sqrDist, extDet; + + if ( det >= 0 ) { + + // The ray and segment are not parallel. + + s0 = a01 * b1 - b0; + s1 = a01 * b0 - b1; + extDet = segExtent * det; + + if ( s0 >= 0 ) { + + if ( s1 >= - extDet ) { + + if ( s1 <= extDet ) { + + // region 0 + // Minimum at interior points of ray and segment. + + var invDet = 1 / det; + s0 *= invDet; + s1 *= invDet; + sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; + + } else { + + // region 1 + + s1 = segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } + + } else { + + // region 5 + + s1 = - segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } + + } else { + + if ( s1 <= - extDet) { + + // region 4 + + s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } else if ( s1 <= extDet ) { + + // region 3 + + s0 = 0; + s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = s1 * ( s1 + 2 * b1 ) + c; + + } else { + + // region 2 + + s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } + + } + + } else { + + // Ray and segment are parallel. + + s1 = ( a01 > 0 ) ? - segExtent : segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + + } + + if ( optionalPointOnRay ) { + + optionalPointOnRay.copy( this.direction.clone().multiplyScalar( s0 ).add( this.origin ) ); + + } + + if ( optionalPointOnSegment ) { + + optionalPointOnSegment.copy( segDir.clone().multiplyScalar( s1 ).add( segCenter ) ); + + } + + return sqrDist; + + }, + + isIntersectionSphere: function ( sphere ) { + + return this.distanceToPoint( sphere.center ) <= sphere.radius; + + }, + + isIntersectionPlane: function ( plane ) { + + // check if the ray lies on the plane first + + var distToPoint = plane.distanceToPoint( this.origin ); + + if ( distToPoint === 0 ) { + + return true; + + } + + var denominator = plane.normal.dot( this.direction ); + + if ( denominator * distToPoint < 0 ) { + + return true + + } + + // ray origin is behind the plane (and is pointing behind it) + + return false; + + }, + + distanceToPlane: function ( plane ) { + + var denominator = plane.normal.dot( this.direction ); + if ( denominator == 0 ) { + + // line is coplanar, return origin + if( plane.distanceToPoint( this.origin ) == 0 ) { + + return 0; + + } + + // Null is preferable to undefined since undefined means.... it is undefined + + return null; + + } + + var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; + + // Return if the ray never intersects the plane + + return t >= 0 ? t : null; + + }, + + intersectPlane: function ( plane, optionalTarget ) { + + var t = this.distanceToPlane( plane ); + + if ( t === null ) { + + return null; + } + + return this.at( t, optionalTarget ); + + }, + + isIntersectionBox: function () { + + var v = new THREE.Vector3(); + + return function ( box ) { + + return this.intersectBox( box, v ) !== null; + + } + + }(), + + intersectBox: function ( box , optionalTarget ) { + + // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ + + var tmin,tmax,tymin,tymax,tzmin,tzmax; + + var invdirx = 1/this.direction.x, + invdiry = 1/this.direction.y, + invdirz = 1/this.direction.z; + + var origin = this.origin; + + if (invdirx >= 0) { + + tmin = (box.min.x - origin.x) * invdirx; + tmax = (box.max.x - origin.x) * invdirx; + + } else { + + tmin = (box.max.x - origin.x) * invdirx; + tmax = (box.min.x - origin.x) * invdirx; + } + + if (invdiry >= 0) { + + tymin = (box.min.y - origin.y) * invdiry; + tymax = (box.max.y - origin.y) * invdiry; + + } else { + + tymin = (box.max.y - origin.y) * invdiry; + tymax = (box.min.y - origin.y) * invdiry; + } + + if ((tmin > tymax) || (tymin > tmax)) return null; + + // These lines also handle the case where tmin or tmax is NaN + // (result of 0 * Infinity). x !== x returns true if x is NaN + + if (tymin > tmin || tmin !== tmin ) tmin = tymin; + + if (tymax < tmax || tmax !== tmax ) tmax = tymax; + + if (invdirz >= 0) { + + tzmin = (box.min.z - origin.z) * invdirz; + tzmax = (box.max.z - origin.z) * invdirz; + + } else { + + tzmin = (box.max.z - origin.z) * invdirz; + tzmax = (box.min.z - origin.z) * invdirz; + } + + if ((tmin > tzmax) || (tzmin > tmax)) return null; + + if (tzmin > tmin || tmin !== tmin ) tmin = tzmin; + + if (tzmax < tmax || tmax !== tmax ) tmax = tzmax; + + //return point closest to the ray (positive side) + + if ( tmax < 0 ) return null; + + return this.at( tmin >= 0 ? tmin : tmax, optionalTarget ); + + }, + + intersectTriangle: function() { + + // Compute the offset origin, edges, and normal. + var diff = new THREE.Vector3(); + var edge1 = new THREE.Vector3(); + var edge2 = new THREE.Vector3(); + var normal = new THREE.Vector3(); + + return function ( a, b, c, backfaceCulling, optionalTarget ) { + + // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp + + edge1.subVectors( b, a ); + edge2.subVectors( c, a ); + normal.crossVectors( edge1, edge2 ); + + // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, + // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by + // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) + // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) + // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) + var DdN = this.direction.dot( normal ); + var sign; + + if ( DdN > 0 ) { + + if ( backfaceCulling ) return null; + sign = 1; + + } else if ( DdN < 0 ) { + + sign = - 1; + DdN = - DdN; + + } else { + + return null; + + } + + diff.subVectors( this.origin, a ); + var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) ); + + // b1 < 0, no intersection + if ( DdQxE2 < 0 ) { + + return null; + + } + + var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) ); + + // b2 < 0, no intersection + if ( DdE1xQ < 0 ) { + + return null; + + } + + // b1+b2 > 1, no intersection + if ( DdQxE2 + DdE1xQ > DdN ) { + + return null; + + } + + // Line intersects triangle, check if ray does. + var QdN = - sign * diff.dot( normal ); + + // t < 0, no intersection + if ( QdN < 0 ) { + + return null; + + } + + // Ray intersects triangle. + return this.at( QdN / DdN, optionalTarget ); + + } + + }(), + + applyMatrix4: function ( matrix4 ) { + + this.direction.add( this.origin ).applyMatrix4( matrix4 ); + this.origin.applyMatrix4( matrix4 ); + this.direction.sub( this.origin ); + this.direction.normalize(); + + return this; + }, + + equals: function ( ray ) { + + return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); + + }, + + clone: function () { + + return new THREE.Ray().copy( this ); + + } + +}; + +/** + * @author bhouston / http://exocortex.com + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Sphere = function ( center, radius ) { + + this.center = ( center !== undefined ) ? center : new THREE.Vector3(); + this.radius = ( radius !== undefined ) ? radius : 0; + +}; + +THREE.Sphere.prototype = { + + constructor: THREE.Sphere, + + set: function ( center, radius ) { + + this.center.copy( center ); + this.radius = radius; + + return this; + }, + + + setFromPoints: function () { + + var box = new THREE.Box3(); + + return function ( points, optionalCenter ) { + + var center = this.center; + + if ( optionalCenter !== undefined ) { + + center.copy( optionalCenter ); + + } else { + + box.setFromPoints( points ).center( center ); + + } + + var maxRadiusSq = 0, cx = center.x, cy = center.y, cz = center.z; + + for ( var i = 0, il = points.length; i < il; i ++ ) { + + var pt = points[ i ]; + var dx = cx - pt.x; + var dy = cy - pt.y; + var dz = cz - pt.z; + + var distanceSquared = dx * dx + dy * dy + dz * dz; + + maxRadiusSq = Math.max( maxRadiusSq, distanceSquared ); + + } + + this.radius = Math.sqrt( maxRadiusSq ); + + return this; + + }; + + }(), + + copy: function ( sphere ) { + + this.center.copy( sphere.center ); + this.radius = sphere.radius; + + return this; + + }, + + empty: function () { + + return ( this.radius <= 0 ); + + }, + + containsPoint: function ( point ) { + + return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); + + }, + + distanceToPoint: function ( point ) { + + return ( point.distanceTo( this.center ) - this.radius ); + + }, + + intersectsSphere: function ( sphere ) { + + var radiusSum = this.radius + sphere.radius; + + return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); + + }, + + clampPoint: function ( point, optionalTarget ) { + + var deltaLengthSq = this.center.distanceToSquared( point ); + + var result = optionalTarget || new THREE.Vector3(); + result.copy( point ); + + if ( deltaLengthSq > ( this.radius * this.radius ) ) { + + result.sub( this.center ).normalize(); + result.multiplyScalar( this.radius ).add( this.center ); + + } + + return result; + + }, + + getBoundingBox: function ( optionalTarget ) { + + var box = optionalTarget || new THREE.Box3(); + + box.set( this.center, this.center ); + box.expandByScalar( this.radius ); + + return box; + + }, + + applyMatrix4: function ( matrix ) { + + this.center.applyMatrix4( matrix ); + this.radius = this.radius * matrix.getMaxScaleOnAxis(); + + return this; + + }, + + translate: function ( offset ) { + + this.center.add( offset ); + + return this; + + }, + + equals: function ( sphere ) { + + return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); + + }, + + clone: function () { + + return new THREE.Sphere().copy( this ); + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author bhouston / http://exocortex.com + */ + +THREE.Frustum = function ( p0, p1, p2, p3, p4, p5 ) { + + this.planes = [ + + ( p0 !== undefined ) ? p0 : new THREE.Plane(), + ( p1 !== undefined ) ? p1 : new THREE.Plane(), + ( p2 !== undefined ) ? p2 : new THREE.Plane(), + ( p3 !== undefined ) ? p3 : new THREE.Plane(), + ( p4 !== undefined ) ? p4 : new THREE.Plane(), + ( p5 !== undefined ) ? p5 : new THREE.Plane() + + ]; + +}; + +THREE.Frustum.prototype = { + + constructor: THREE.Frustum, + + set: function ( p0, p1, p2, p3, p4, p5 ) { + + var planes = this.planes; + + planes[0].copy( p0 ); + planes[1].copy( p1 ); + planes[2].copy( p2 ); + planes[3].copy( p3 ); + planes[4].copy( p4 ); + planes[5].copy( p5 ); + + return this; + + }, + + copy: function ( frustum ) { + + var planes = this.planes; + + for( var i = 0; i < 6; i ++ ) { + + planes[i].copy( frustum.planes[i] ); + + } + + return this; + + }, + + setFromMatrix: function ( m ) { + + var planes = this.planes; + var me = m.elements; + var me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3]; + var me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7]; + var me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11]; + var me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15]; + + planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); + planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); + planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); + planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); + planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); + planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); + + return this; + + }, + + intersectsObject: function () { + + var sphere = new THREE.Sphere(); + + return function ( object ) { + + var geometry = object.geometry; + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( object.matrixWorld ); + + return this.intersectsSphere( sphere ); + + }; + + }(), + + intersectsSphere: function ( sphere ) { + + var planes = this.planes; + var center = sphere.center; + var negRadius = -sphere.radius; + + for ( var i = 0; i < 6; i ++ ) { + + var distance = planes[ i ].distanceToPoint( center ); + + if ( distance < negRadius ) { + + return false; + + } + + } + + return true; + + }, + + intersectsBox : function() { + + var p1 = new THREE.Vector3(), + p2 = new THREE.Vector3(); + + return function( box ) { + + var planes = this.planes; + + for ( var i = 0; i < 6 ; i ++ ) { + + var plane = planes[i]; + + p1.x = plane.normal.x > 0 ? box.min.x : box.max.x; + p2.x = plane.normal.x > 0 ? box.max.x : box.min.x; + p1.y = plane.normal.y > 0 ? box.min.y : box.max.y; + p2.y = plane.normal.y > 0 ? box.max.y : box.min.y; + p1.z = plane.normal.z > 0 ? box.min.z : box.max.z; + p2.z = plane.normal.z > 0 ? box.max.z : box.min.z; + + var d1 = plane.distanceToPoint( p1 ); + var d2 = plane.distanceToPoint( p2 ); + + // if both outside plane, no intersection + + if ( d1 < 0 && d2 < 0 ) { + + return false; + + } + } + + return true; + }; + + }(), + + + containsPoint: function ( point ) { + + var planes = this.planes; + + for ( var i = 0; i < 6; i ++ ) { + + if ( planes[ i ].distanceToPoint( point ) < 0 ) { + + return false; + + } + + } + + return true; + + }, + + clone: function () { + + return new THREE.Frustum().copy( this ); + + } + +}; + +/** + * @author bhouston / http://exocortex.com + */ + +THREE.Plane = function ( normal, constant ) { + + this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 ); + this.constant = ( constant !== undefined ) ? constant : 0; + +}; + +THREE.Plane.prototype = { + + constructor: THREE.Plane, + + set: function ( normal, constant ) { + + this.normal.copy( normal ); + this.constant = constant; + + return this; + + }, + + setComponents: function ( x, y, z, w ) { + + this.normal.set( x, y, z ); + this.constant = w; + + return this; + + }, + + setFromNormalAndCoplanarPoint: function ( normal, point ) { + + this.normal.copy( normal ); + this.constant = - point.dot( this.normal ); // must be this.normal, not normal, as this.normal is normalized + + return this; + + }, + + setFromCoplanarPoints: function() { + + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + + return function ( a, b, c ) { + + var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize(); + + // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? + + this.setFromNormalAndCoplanarPoint( normal, a ); + + return this; + + }; + + }(), + + + copy: function ( plane ) { + + this.normal.copy( plane.normal ); + this.constant = plane.constant; + + return this; + + }, + + normalize: function () { + + // Note: will lead to a divide by zero if the plane is invalid. + + var inverseNormalLength = 1.0 / this.normal.length(); + this.normal.multiplyScalar( inverseNormalLength ); + this.constant *= inverseNormalLength; + + return this; + + }, + + negate: function () { + + this.constant *= -1; + this.normal.negate(); + + return this; + + }, + + distanceToPoint: function ( point ) { + + return this.normal.dot( point ) + this.constant; + + }, + + distanceToSphere: function ( sphere ) { + + return this.distanceToPoint( sphere.center ) - sphere.radius; + + }, + + projectPoint: function ( point, optionalTarget ) { + + return this.orthoPoint( point, optionalTarget ).sub( point ).negate(); + + }, + + orthoPoint: function ( point, optionalTarget ) { + + var perpendicularMagnitude = this.distanceToPoint( point ); + + var result = optionalTarget || new THREE.Vector3(); + return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude ); + + }, + + isIntersectionLine: function ( line ) { + + // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. + + var startSign = this.distanceToPoint( line.start ); + var endSign = this.distanceToPoint( line.end ); + + return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); + + }, + + intersectLine: function() { + + var v1 = new THREE.Vector3(); + + return function ( line, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + + var direction = line.delta( v1 ); + + var denominator = this.normal.dot( direction ); + + if ( denominator == 0 ) { + + // line is coplanar, return origin + if( this.distanceToPoint( line.start ) == 0 ) { + + return result.copy( line.start ); + + } + + // Unsure if this is the correct method to handle this case. + return undefined; + + } + + var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; + + if( t < 0 || t > 1 ) { + + return undefined; + + } + + return result.copy( direction ).multiplyScalar( t ).add( line.start ); + + }; + + }(), + + + coplanarPoint: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.copy( this.normal ).multiplyScalar( - this.constant ); + + }, + + applyMatrix4: function() { + + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + var m1 = new THREE.Matrix3(); + + return function ( matrix, optionalNormalMatrix ) { + + if ( ! ( matrix instanceof THREE.Matrix4 ) ) return THREE.onerror( 'expecting a Matrix4', matrix ); + + // compute new normal based on theory here: + // http://www.songho.ca/opengl/gl_normaltransform.html + var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); + var newNormal = v1.copy( this.normal ).applyMatrix3( normalMatrix ); + + var newCoplanarPoint = this.coplanarPoint( v2 ); + newCoplanarPoint.applyMatrix4( matrix ); + + this.setFromNormalAndCoplanarPoint( newNormal, newCoplanarPoint ); + + return this; + + }; + + }(), + + translate: function ( offset ) { + + this.constant = this.constant - offset.dot( this.normal ); + + return this; + + }, + + equals: function ( plane ) { + + return plane.normal.equals( this.normal ) && ( plane.constant == this.constant ); + + }, + + clone: function () { + + return new THREE.Plane().copy( this ); + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Math = { + + PI2: Math.PI * 2, + DegreeToRadiansFactor: Math.PI / 180, + RadianToDegreesFactor: 180 / Math.PI, + + generateUUID: function () { + + // http://www.broofa.com/Tools/Math.uuid.htm + + var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); + var uuid = new Array(36); + var rnd = 0, r; + + return function () { + + for ( var i = 0; i < 36; i ++ ) { + + if ( i == 8 || i == 13 || i == 18 || i == 23 ) { + + uuid[ i ] = '-'; + + } else if ( i == 14 ) { + + uuid[ i ] = '4'; + + } else { + + if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0; + r = rnd & 0xf; + rnd = rnd >> 4; + uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; + + } + } + + return uuid.join(''); + + }; + + }(), + + // Clamp value to range + + clamp: function ( x, a, b ) { + + return ( x < a ) ? a : ( ( x > b ) ? b : x ); + + }, + + // Clamp value to range to range + + mapLinear: function ( x, a1, a2, b1, b2 ) { + + return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); + + }, + + // http://en.wikipedia.org/wiki/Smoothstep + + smoothstep: function ( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min )/( max - min ); + + return x*x*(3 - 2*x); + + }, + + smootherstep: function ( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min )/( max - min ); + + return x*x*x*(x*(x*6 - 15) + 10); + + }, + + // Random float from <0, 1> with 16 bits of randomness + // (standard Math.random() creates repetitive patterns when applied over larger space) + + random16: function () { + + return ( 65280 * Math.random() + 255 * Math.random() ) / 65535; + + }, + + // Random integer from interval + + randInt: function ( low, high ) { + + return low + Math.floor( Math.random() * ( high - low + 1 ) ); + + }, + + // Random float from interval + + randFloat: function ( low, high ) { + + return low + Math.random() * ( high - low ); + + }, + + // Random float from <-range/2, range/2> interval + + randFloatSpread: function ( range ) { + + return range * ( 0.5 - Math.random() ); + + }, + + sign: function ( x ) { + + return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : 0; + + }, + + degToRad: function ( degrees ) { + + return degrees * this.DegreeToRadiansFactor; + + }, + + radToDeg: function ( radians ) { + + return radians * this.RadianToDegreesFactor; + + }, + + isPowerOfTwo: function ( value ) { + return ( value & ( value - 1 ) ) === 0 && value !== 0; + } + +}; + +/** + * Spline from Tween.js, slightly optimized (and trashed) + * http://sole.github.com/tween.js/examples/05_spline.html + * + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Spline = function ( points ) { + + this.points = points; + + var c = [], v3 = { x: 0, y: 0, z: 0 }, + point, intPoint, weight, w2, w3, + pa, pb, pc, pd; + + this.initFromArray = function( a ) { + + this.points = []; + + for ( var i = 0; i < a.length; i++ ) { + + this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] }; + + } + + }; + + this.getPoint = function ( k ) { + + point = ( this.points.length - 1 ) * k; + intPoint = Math.floor( point ); + weight = point - intPoint; + + c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > this.points.length - 2 ? this.points.length - 1 : intPoint + 1; + c[ 3 ] = intPoint > this.points.length - 3 ? this.points.length - 1 : intPoint + 2; + + pa = this.points[ c[ 0 ] ]; + pb = this.points[ c[ 1 ] ]; + pc = this.points[ c[ 2 ] ]; + pd = this.points[ c[ 3 ] ]; + + w2 = weight * weight; + w3 = weight * w2; + + v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 ); + v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 ); + v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 ); + + return v3; + + }; + + this.getControlPointsArray = function () { + + var i, p, l = this.points.length, + coords = []; + + for ( i = 0; i < l; i ++ ) { + + p = this.points[ i ]; + coords[ i ] = [ p.x, p.y, p.z ]; + + } + + return coords; + + }; + + // approximate length by summing linear segments + + this.getLength = function ( nSubDivisions ) { + + var i, index, nSamples, position, + point = 0, intPoint = 0, oldIntPoint = 0, + oldPosition = new THREE.Vector3(), + tmpVec = new THREE.Vector3(), + chunkLengths = [], + totalLength = 0; + + // first point has 0 length + + chunkLengths[ 0 ] = 0; + + if ( !nSubDivisions ) nSubDivisions = 100; + + nSamples = this.points.length * nSubDivisions; + + oldPosition.copy( this.points[ 0 ] ); + + for ( i = 1; i < nSamples; i ++ ) { + + index = i / nSamples; + + position = this.getPoint( index ); + tmpVec.copy( position ); + + totalLength += tmpVec.distanceTo( oldPosition ); + + oldPosition.copy( position ); + + point = ( this.points.length - 1 ) * index; + intPoint = Math.floor( point ); + + if ( intPoint != oldIntPoint ) { + + chunkLengths[ intPoint ] = totalLength; + oldIntPoint = intPoint; + + } + + } + + // last point ends with total length + + chunkLengths[ chunkLengths.length ] = totalLength; + + return { chunks: chunkLengths, total: totalLength }; + + }; + + this.reparametrizeByArcLength = function ( samplingCoef ) { + + var i, j, + index, indexCurrent, indexNext, + linearDistance, realDistance, + sampling, position, + newpoints = [], + tmpVec = new THREE.Vector3(), + sl = this.getLength(); + + newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() ); + + for ( i = 1; i < this.points.length; i++ ) { + + //tmpVec.copy( this.points[ i - 1 ] ); + //linearDistance = tmpVec.distanceTo( this.points[ i ] ); + + realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ]; + + sampling = Math.ceil( samplingCoef * realDistance / sl.total ); + + indexCurrent = ( i - 1 ) / ( this.points.length - 1 ); + indexNext = i / ( this.points.length - 1 ); + + for ( j = 1; j < sampling - 1; j++ ) { + + index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent ); + + position = this.getPoint( index ); + newpoints.push( tmpVec.copy( position ).clone() ); + + } + + newpoints.push( tmpVec.copy( this.points[ i ] ).clone() ); + + } + + this.points = newpoints; + + }; + + // Catmull-Rom + + function interpolate( p0, p1, p2, p3, t, t2, t3 ) { + + var v0 = ( p2 - p0 ) * 0.5, + v1 = ( p3 - p1 ) * 0.5; + + return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; + + }; + +}; + +/** + * @author bhouston / http://exocortex.com + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Triangle = function ( a, b, c ) { + + this.a = ( a !== undefined ) ? a : new THREE.Vector3(); + this.b = ( b !== undefined ) ? b : new THREE.Vector3(); + this.c = ( c !== undefined ) ? c : new THREE.Vector3(); + +}; + +THREE.Triangle.normal = function() { + + var v0 = new THREE.Vector3(); + + return function ( a, b, c, optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + + result.subVectors( c, b ); + v0.subVectors( a, b ); + result.cross( v0 ); + + var resultLengthSq = result.lengthSq(); + if( resultLengthSq > 0 ) { + + return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); + + } + + return result.set( 0, 0, 0 ); + + }; + +}(); + +// static/instance method to calculate barycoordinates +// based on: http://www.blackpawn.com/texts/pointinpoly/default.html +THREE.Triangle.barycoordFromPoint = function() { + + var v0 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + + return function ( point, a, b, c, optionalTarget ) { + + v0.subVectors( c, a ); + v1.subVectors( b, a ); + v2.subVectors( point, a ); + + var dot00 = v0.dot( v0 ); + var dot01 = v0.dot( v1 ); + var dot02 = v0.dot( v2 ); + var dot11 = v1.dot( v1 ); + var dot12 = v1.dot( v2 ); + + var denom = ( dot00 * dot11 - dot01 * dot01 ); + + var result = optionalTarget || new THREE.Vector3(); + + // colinear or singular triangle + if( denom == 0 ) { + // arbitrary location outside of triangle? + // not sure if this is the best idea, maybe should be returning undefined + return result.set( -2, -1, -1 ); + } + + var invDenom = 1 / denom; + var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; + var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; + + // barycoordinates must always sum to 1 + return result.set( 1 - u - v, v, u ); + + }; + +}(); + +THREE.Triangle.containsPoint = function() { + + var v1 = new THREE.Vector3(); + + return function ( point, a, b, c ) { + + var result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 ); + + return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); + + }; + +}(); + +THREE.Triangle.prototype = { + + constructor: THREE.Triangle, + + set: function ( a, b, c ) { + + this.a.copy( a ); + this.b.copy( b ); + this.c.copy( c ); + + return this; + + }, + + setFromPointsAndIndices: function ( points, i0, i1, i2 ) { + + this.a.copy( points[i0] ); + this.b.copy( points[i1] ); + this.c.copy( points[i2] ); + + return this; + + }, + + copy: function ( triangle ) { + + this.a.copy( triangle.a ); + this.b.copy( triangle.b ); + this.c.copy( triangle.c ); + + return this; + + }, + + area: function() { + + var v0 = new THREE.Vector3(); + var v1 = new THREE.Vector3(); + + return function () { + + v0.subVectors( this.c, this.b ); + v1.subVectors( this.a, this.b ); + + return v0.cross( v1 ).length() * 0.5; + + }; + + }(), + + midpoint: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Vector3(); + return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); + + }, + + normal: function ( optionalTarget ) { + + return THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget ); + + }, + + plane: function ( optionalTarget ) { + + var result = optionalTarget || new THREE.Plane(); + + return result.setFromCoplanarPoints( this.a, this.b, this.c ); + + }, + + barycoordFromPoint: function ( point, optionalTarget ) { + + return THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); + + }, + + containsPoint: function ( point ) { + + return THREE.Triangle.containsPoint( point, this.a, this.b, this.c ); + + }, + + equals: function ( triangle ) { + + return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); + + }, + + clone: function () { + + return new THREE.Triangle().copy( this ); + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Vertex = function ( v ) { + + return THREE.onerror( 'THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.' ); + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.UV = function ( u, v ) { + + THREE.onerror( 'THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.') + return new THREE.Vector2( u, v ); + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Clock = function ( autoStart ) { + + this.autoStart = ( autoStart !== undefined ) ? autoStart : true; + + this.startTime = 0; + this.oldTime = 0; + this.elapsedTime = 0; + + this.running = false; + +}; + +THREE.Clock.prototype = { + + constructor: THREE.Clock, + + start: function () { + + this.startTime = self.performance !== undefined && self.performance.now !== undefined + ? self.performance.now() + : Date.now(); + + this.oldTime = this.startTime; + this.running = true; + }, + + stop: function () { + + this.getElapsedTime(); + this.running = false; + + }, + + getElapsedTime: function () { + + this.getDelta(); + return this.elapsedTime; + + }, + + getDelta: function () { + + var diff = 0; + + if ( this.autoStart && ! this.running ) { + + this.start(); + + } + + if ( this.running ) { + + var newTime = self.performance !== undefined && self.performance.now !== undefined + ? self.performance.now() + : Date.now(); + + diff = 0.001 * ( newTime - this.oldTime ); + this.oldTime = newTime; + + this.elapsedTime += diff; + + } + + return diff; + + } + +}; + +/** + * https://github.com/mrdoob/eventdispatcher.js/ + */ + +THREE.EventDispatcher = function () {} + +THREE.EventDispatcher.prototype = { + + constructor: THREE.EventDispatcher, + + apply: function ( object ) { + + object.addEventListener = THREE.EventDispatcher.prototype.addEventListener; + object.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener; + object.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener; + object.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent; + + }, + + addEventListener: function ( type, listener ) { + + if ( this._listeners === undefined ) this._listeners = {}; + + var listeners = this._listeners; + + if ( listeners[ type ] === undefined ) { + + listeners[ type ] = []; + + } + + if ( listeners[ type ].indexOf( listener ) === - 1 ) { + + listeners[ type ].push( listener ); + + } + + }, + + hasEventListener: function ( type, listener ) { + + if ( this._listeners === undefined ) return false; + + var listeners = this._listeners; + + if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) { + + return true; + + } + + return false; + + }, + + removeEventListener: function ( type, listener ) { + + if ( this._listeners === undefined ) return; + + var listeners = this._listeners; + var listenerArray = listeners[ type ]; + + if ( listenerArray !== undefined ) { + + var index = listenerArray.indexOf( listener ); + + if ( index !== - 1 ) { + + listenerArray.splice( index, 1 ); + + } + + } + + }, + + dispatchEvent: function () { + + var array = []; + + return function ( event ) { + + if ( this._listeners === undefined ) return; + + var listeners = this._listeners; + var listenerArray = listeners[ event.type ]; + + if ( listenerArray !== undefined ) { + + event.target = this; + + var length = listenerArray.length; + + for ( var i = 0; i < length; i ++ ) { + + array[ i ] = listenerArray[ i ]; + + } + + for ( var i = 0; i < length; i ++ ) { + + array[ i ].call( this, event ); + + } + + } + + }; + + }() + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author bhouston / http://exocortex.com/ + * @author stephomi / http://stephaneginier.com/ + */ + +( function ( THREE ) { + + THREE.Raycaster = function ( origin, direction, near, far ) { + + this.ray = new THREE.Ray( origin, direction ); + // direction is assumed to be normalized (for accurate distance calculations) + + this.near = near || 0; + this.far = far || Infinity; + + }; + + var sphere = new THREE.Sphere(); + var localRay = new THREE.Ray(); + var facePlane = new THREE.Plane(); + var intersectPoint = new THREE.Vector3(); + var matrixPosition = new THREE.Vector3(); + + var inverseMatrix = new THREE.Matrix4(); + + var descSort = function ( a, b ) { + + return a.distance - b.distance; + + }; + + var vA = new THREE.Vector3(); + var vB = new THREE.Vector3(); + var vC = new THREE.Vector3(); + + var intersectObject = function ( object, raycaster, intersects ) { + + if ( object instanceof THREE.Sprite ) { + + matrixPosition.setFromMatrixPosition( object.matrixWorld ); + + var distance = raycaster.ray.distanceToPoint( matrixPosition ); + + if ( distance > object.scale.x ) { + + return intersects; + + } + + intersects.push( { + + distance: distance, + point: object.position, + face: null, + object: object + + } ); + + } else if ( object instanceof THREE.LOD ) { + + matrixPosition.setFromMatrixPosition( object.matrixWorld ); + var distance = raycaster.ray.origin.distanceTo( matrixPosition ); + + intersectObject( object.getObjectForDistance( distance ), raycaster, intersects ); + + } else if ( object instanceof THREE.Mesh ) { + + var geometry = object.geometry; + + // Checking boundingSphere distance to ray + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( object.matrixWorld ); + + if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { + + return intersects; + + } + + // Check boundingBox before continuing + + inverseMatrix.getInverse( object.matrixWorld ); + localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + + if ( geometry.boundingBox !== null ) { + + if ( localRay.isIntersectionBox( geometry.boundingBox ) === false ) { + + return intersects; + + } + + } + + if ( geometry instanceof THREE.BufferGeometry ) { + + var material = object.material; + + if ( material === undefined ) return intersects; + + var attributes = geometry.attributes; + + var a, b, c; + var precision = raycaster.precision; + + if ( attributes.index !== undefined ) { + + var offsets = geometry.offsets; + var indices = attributes.index.array; + var positions = attributes.position.array; + + for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) { + + var start = offsets[ oi ].start; + var count = offsets[ oi ].count; + var index = offsets[ oi ].index; + + for ( var i = start, il = start + count; i < il; i += 3 ) { + + a = index + indices[ i ]; + b = index + indices[ i + 1 ]; + c = index + indices[ i + 2 ]; + + vA.set( + positions[ a * 3 ], + positions[ a * 3 + 1 ], + positions[ a * 3 + 2 ] + ); + vB.set( + positions[ b * 3 ], + positions[ b * 3 + 1 ], + positions[ b * 3 + 2 ] + ); + vC.set( + positions[ c * 3 ], + positions[ c * 3 + 1 ], + positions[ c * 3 + 2 ] + ); + + + if ( material.side === THREE.BackSide ) { + + var intersectionPoint = localRay.intersectTriangle( vC, vB, vA, true ); + + } else { + + var intersectionPoint = localRay.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); + + } + + if ( intersectionPoint === null ) continue; + + intersectionPoint.applyMatrix4( object.matrixWorld ); + + var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); + + if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; + + intersects.push( { + + distance: distance, + point: intersectionPoint, + indices: [a, b, c], + face: null, + faceIndex: null, + object: object + + } ); + + } + + } + + } else { + + var offsets = geometry.offsets; + var positions = attributes.position.array; + + for ( var i = 0, il = attributes.position.array.length; i < il; i += 3 ) { + + a = i; + b = i + 1; + c = i + 2; + + vA.set( + positions[ a * 3 ], + positions[ a * 3 + 1 ], + positions[ a * 3 + 2 ] + ); + vB.set( + positions[ b * 3 ], + positions[ b * 3 + 1 ], + positions[ b * 3 + 2 ] + ); + vC.set( + positions[ c * 3 ], + positions[ c * 3 + 1 ], + positions[ c * 3 + 2 ] + ); + + + if ( material.side === THREE.BackSide ) { + + var intersectionPoint = localRay.intersectTriangle( vC, vB, vA, true ); + + } else { + + var intersectionPoint = localRay.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); + + } + + if ( intersectionPoint === null ) continue; + + intersectionPoint.applyMatrix4( object.matrixWorld ); + + var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); + + if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; + + intersects.push( { + + distance: distance, + point: intersectionPoint, + indices: [a, b, c], + face: null, + faceIndex: null, + object: object + + } ); + + } + + } + + } else if ( geometry instanceof THREE.Geometry ) { + + var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; + var objectMaterials = isFaceMaterial === true ? object.material.materials : null; + + var a, b, c, d; + var precision = raycaster.precision; + + var vertices = geometry.vertices; + + for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { + + var face = geometry.faces[ f ]; + + var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : object.material; + + if ( material === undefined ) continue; + + a = vertices[ face.a ]; + b = vertices[ face.b ]; + c = vertices[ face.c ]; + + if ( material.morphTargets === true ) { + + var morphTargets = geometry.morphTargets; + var morphInfluences = object.morphTargetInfluences; + + vA.set( 0, 0, 0 ); + vB.set( 0, 0, 0 ); + vC.set( 0, 0, 0 ); + + for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { + + var influence = morphInfluences[ t ]; + + if ( influence === 0 ) continue; + + var targets = morphTargets[ t ].vertices; + + vA.x += ( targets[ face.a ].x - a.x ) * influence; + vA.y += ( targets[ face.a ].y - a.y ) * influence; + vA.z += ( targets[ face.a ].z - a.z ) * influence; + + vB.x += ( targets[ face.b ].x - b.x ) * influence; + vB.y += ( targets[ face.b ].y - b.y ) * influence; + vB.z += ( targets[ face.b ].z - b.z ) * influence; + + vC.x += ( targets[ face.c ].x - c.x ) * influence; + vC.y += ( targets[ face.c ].y - c.y ) * influence; + vC.z += ( targets[ face.c ].z - c.z ) * influence; + + } + + vA.add( a ); + vB.add( b ); + vC.add( c ); + + a = vA; + b = vB; + c = vC; + + } + + if ( material.side === THREE.BackSide ) { + + var intersectionPoint = localRay.intersectTriangle( c, b, a, true ); + + } else { + + var intersectionPoint = localRay.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide ); + + } + + if ( intersectionPoint === null ) continue; + + intersectionPoint.applyMatrix4( object.matrixWorld ); + + var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); + + if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; + + intersects.push( { + + distance: distance, + point: intersectionPoint, + face: face, + faceIndex: f, + object: object + + } ); + + } + + } + + } else if ( object instanceof THREE.Line ) { + + var precision = raycaster.linePrecision; + var precisionSq = precision * precision; + + var geometry = object.geometry; + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + // Checking boundingSphere distance to ray + + sphere.copy( geometry.boundingSphere ); + sphere.applyMatrix4( object.matrixWorld ); + + if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { + + return intersects; + + } + + inverseMatrix.getInverse( object.matrixWorld ); + localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + + /* if ( geometry instanceof THREE.BufferGeometry ) { + + } else */ if ( geometry instanceof THREE.Geometry ) { + + var vertices = geometry.vertices; + var nbVertices = vertices.length; + var interSegment = new THREE.Vector3(); + var interRay = new THREE.Vector3(); + var step = object.type === THREE.LineStrip ? 1 : 2; + + for ( var i = 0; i < nbVertices - 1; i = i + step ) { + + var distSq = localRay.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); + + if ( distSq > precisionSq ) continue; + + var distance = localRay.origin.distanceTo( interRay ); + + if ( distance < raycaster.near || distance > raycaster.far ) continue; + + intersects.push( { + + distance: distance, + // What do we want? intersection point on the ray or on the segment?? + // point: raycaster.ray.at( distance ), + point: interSegment.clone().applyMatrix4( object.matrixWorld ), + face: null, + faceIndex: null, + object: object + + } ); + + } + + } + + } + + }; + + var intersectDescendants = function ( object, raycaster, intersects ) { + + var descendants = object.getDescendants(); + + for ( var i = 0, l = descendants.length; i < l; i ++ ) { + + intersectObject( descendants[ i ], raycaster, intersects ); + + } + }; + + // + + THREE.Raycaster.prototype.precision = 0.0001; + THREE.Raycaster.prototype.linePrecision = 1; + + THREE.Raycaster.prototype.set = function ( origin, direction ) { + + this.ray.set( origin, direction ); + // direction is assumed to be normalized (for accurate distance calculations) + + }; + + THREE.Raycaster.prototype.intersectObject = function ( object, recursive ) { + + var intersects = []; + + if ( recursive === true ) { + + intersectDescendants( object, this, intersects ); + + } + + intersectObject( object, this, intersects ); + + intersects.sort( descSort ); + + return intersects; + + }; + + THREE.Raycaster.prototype.intersectObjects = function ( objects, recursive ) { + + var intersects = []; + + for ( var i = 0, l = objects.length; i < l; i ++ ) { + + intersectObject( objects[ i ], this, intersects ); + + if ( recursive === true ) { + + intersectDescendants( objects[ i ], this, intersects ); + + } + + } + + intersects.sort( descSort ); + + return intersects; + + }; + +}( THREE ) ); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + */ + +THREE.Object3D = function () { + + this.id = THREE.Object3DIdCount ++; + this.uuid = THREE.Math.generateUUID(); + this.className = "Object3D"; + + this.name = ''; + + this.parent = undefined; + this.children = []; + + this.up = new THREE.Vector3( 0, 1, 0 ); + + this.position = new THREE.Vector3(); + this._rotation = new THREE.Euler(); + this._quaternion = new THREE.Quaternion(); + this.scale = new THREE.Vector3( 1, 1, 1 ); + + // keep rotation and quaternion in sync + + this._rotation._quaternion = this.quaternion; + this._quaternion._euler = this.rotation; + + this.renderDepth = null; + + this.rotationAutoUpdate = true; + + this.matrix = new THREE.Matrix4(); + this.matrixWorld = new THREE.Matrix4(); + + this.matrixAutoUpdate = true; + this.matrixWorldNeedsUpdate = true; + + this.visible = true; + + this.castShadow = false; + this.receiveShadow = false; + + this.frustumCulled = true; + + this.userData = {}; + +}; + + +THREE.Object3D.prototype = { + + constructor: THREE.Object3D, + + get rotation () { + return this._rotation; + }, + + set rotation ( value ) { + + this._rotation = value; + this._rotation._quaternion = this._quaternion; + this._quaternion._euler = this._rotation; + this._rotation._updateQuaternion(); + + }, + + get quaternion () { + return this._quaternion; + }, + + set quaternion ( value ) { + + this._quaternion = value; + this._quaternion._euler = this._rotation; + this._rotation._quaternion = this._quaternion; + this._quaternion._updateEuler(); + + }, + + get eulerOrder () { + + THREE.onwarning( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); + + return this.rotation.order; + + }, + + set eulerOrder ( value ) { + + THREE.onwarning( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); + + this.rotation.order = value; + + }, + + get useQuaternion () { + + THREE.onwarning( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); + + }, + + set useQuaternion ( value ) { + + THREE.onwarning( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); + + }, + + applyMatrix: function ( matrix ) { + + this.matrix.multiplyMatrices( matrix, this.matrix ); + + this.matrix.decompose( this.position, this.quaternion, this.scale ); + + }, + + setRotationFromAxisAngle: function ( axis, angle ) { + + // assumes axis is normalized + + this.quaternion.setFromAxisAngle( axis, angle ); + + }, + + setRotationFromEuler: function ( euler ) { + + this.quaternion.setFromEuler( euler, true ); + + }, + + setRotationFromMatrix: function ( m ) { + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + this.quaternion.setFromRotationMatrix( m ); + + }, + + setRotationFromQuaternion: function ( q ) { + + // assumes q is normalized + + this.quaternion.copy( q ); + + }, + + rotateOnAxis: function() { + + // rotate object on axis in object space + // axis is assumed to be normalized + + var q1 = new THREE.Quaternion(); + + return function ( axis, angle ) { + + q1.setFromAxisAngle( axis, angle ); + + this.quaternion.multiply( q1 ); + + return this; + + } + + }(), + + rotateX: function () { + + var v1 = new THREE.Vector3( 1, 0, 0 ); + + return function ( angle ) { + + return this.rotateOnAxis( v1, angle ); + + }; + + }(), + + rotateY: function () { + + var v1 = new THREE.Vector3( 0, 1, 0 ); + + return function ( angle ) { + + return this.rotateOnAxis( v1, angle ); + + }; + + }(), + + rotateZ: function () { + + var v1 = new THREE.Vector3( 0, 0, 1 ); + + return function ( angle ) { + + return this.rotateOnAxis( v1, angle ); + + }; + + }(), + + translateOnAxis: function () { + + // translate object by distance along axis in object space + // axis is assumed to be normalized + + var v1 = new THREE.Vector3(); + + return function ( axis, distance ) { + + v1.copy( axis ); + + v1.applyQuaternion( this.quaternion ); + + this.position.add( v1.multiplyScalar( distance ) ); + + return this; + + } + + }(), + + translate: function ( distance, axis ) { + + THREE.onwarning( 'DEPRECATED: Object3D\'s .translate() has been removed. Use .translateOnAxis( axis, distance ) instead. Note args have been changed.' ); + return this.translateOnAxis( axis, distance ); + + }, + + translateX: function () { + + var v1 = new THREE.Vector3( 1, 0, 0 ); + + return function ( distance ) { + + return this.translateOnAxis( v1, distance ); + + }; + + }(), + + translateY: function () { + + var v1 = new THREE.Vector3( 0, 1, 0 ); + + return function ( distance ) { + + return this.translateOnAxis( v1, distance ); + + }; + + }(), + + translateZ: function () { + + var v1 = new THREE.Vector3( 0, 0, 1 ); + + return function ( distance ) { + + return this.translateOnAxis( v1, distance ); + + }; + + }(), + + localToWorld: function ( vector ) { + + return vector.applyMatrix4( this.matrixWorld ); + + }, + + worldToLocal: function () { + + var m1 = new THREE.Matrix4(); + + return function ( vector ) { + + return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) ); + + }; + + }(), + + lookAt: function () { + + // This routine does not support objects with rotated and/or translated parent(s) + + var m1 = new THREE.Matrix4(); + + return function ( vector ) { + + m1.lookAt( vector, this.position, this.up ); + + this.quaternion.setFromRotationMatrix( m1 ); + + }; + + }(), + + add: function ( object ) { + + if ( object === this ) { + + THREE.onwarning( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' ); + return; + + } + + if ( object instanceof THREE.Object3D ) { + + if ( object.parent !== undefined ) { + + object.parent.remove( object ); + + } + + object.parent = this; + object.dispatchEvent( { type: 'added' } ); + + this.children.push( object ); + + // add to scene + + var scene = this; + + while ( scene.parent !== undefined ) { + + scene = scene.parent; + + } + + if ( scene !== undefined && scene instanceof THREE.Scene ) { + + scene.__addObject( object ); + + } + + } + + }, + + remove: function ( object ) { + + var index = this.children.indexOf( object ); + + if ( index !== - 1 ) { + + object.parent = undefined; + object.dispatchEvent( { type: 'removed' } ); + + this.children.splice( index, 1 ); + + // remove from scene + + var scene = this; + + while ( scene.parent !== undefined ) { + + scene = scene.parent; + + } + + if ( scene !== undefined && scene instanceof THREE.Scene ) { + + scene.__removeObject( object ); + + } + + } + + }, + + traverse: function ( callback ) { + + callback( this ); + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].traverse( callback ); + + } + + }, + + getObjectById: function ( id, recursive ) { + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + var child = this.children[ i ]; + + if ( child.id === id ) { + + return child; + + } + + if ( recursive === true ) { + + child = child.getObjectById( id, recursive ); + + if ( child !== undefined ) { + + return child; + + } + + } + + } + + return undefined; + + }, + + getObjectByName: function ( name, recursive ) { + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + var child = this.children[ i ]; + + if ( child.name === name ) { + + return child; + + } + + if ( recursive === true ) { + + child = child.getObjectByName( name, recursive ); + + if ( child !== undefined ) { + + return child; + + } + + } + + } + + return undefined; + + }, + + getChildByName: function ( name, recursive ) { + + THREE.onwarning( 'DEPRECATED: Object3D\'s .getChildByName() has been renamed to .getObjectByName().' ); + return this.getObjectByName( name, recursive ); + + }, + + getDescendants: function ( array ) { + + if ( array === undefined ) array = []; + + Array.prototype.push.apply( array, this.children ); + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].getDescendants( array ); + + } + + return array; + + }, + + updateMatrix: function () { + + this.matrix.compose( this.position, this.quaternion, this.scale ); + + this.matrixWorldNeedsUpdate = true; + + }, + + updateMatrixWorld: function ( force ) { + + if ( this.matrixAutoUpdate === true ) this.updateMatrix(); + + if ( this.matrixWorldNeedsUpdate === true || force === true ) { + + if ( this.parent === undefined ) { + + this.matrixWorld.copy( this.matrix ); + + } else { + + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + + } + + this.matrixWorldNeedsUpdate = false; + + force = true; + + } + + // update children + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].updateMatrixWorld( force ); + + } + + }, + + clone: function ( object, recursive ) { + + if ( object === undefined ) object = new THREE.Object3D(); + if ( recursive === undefined ) recursive = true; + + object.name = this.name; + + object.up.copy( this.up ); + + object.position.copy( this.position ); + object.quaternion.copy( this.quaternion ); + object.scale.copy( this.scale ); + + object.renderDepth = this.renderDepth; + + object.rotationAutoUpdate = this.rotationAutoUpdate; + + object.matrix.copy( this.matrix ); + object.matrixWorld.copy( this.matrixWorld ); + + object.matrixAutoUpdate = this.matrixAutoUpdate; + object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate; + + object.visible = this.visible; + + object.castShadow = this.castShadow; + object.receiveShadow = this.receiveShadow; + + object.frustumCulled = this.frustumCulled; + + object.userData = JSON.parse( JSON.stringify( this.userData ) ); + + if ( recursive === true ) { + + for ( var i = 0; i < this.children.length; i ++ ) { + + var child = this.children[ i ]; + object.add( child.clone() ); + + } + + } + + return object; + + } + +}; + +THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype ); + +THREE.Object3DIdCount = 0; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author supereggbert / http://www.paulbrunt.co.uk/ + * @author julianwa / https://github.com/julianwa + */ + +THREE.Projector = function () { + + var _object, _objectCount, _objectPool = [], _objectPoolLength = 0, + _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, + _face, _faceCount, _facePool = [], _facePoolLength = 0, + _line, _lineCount, _linePool = [], _linePoolLength = 0, + _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0, + + _renderData = { objects: [], lights: [], elements: [] }, + + _vA = new THREE.Vector3(), + _vB = new THREE.Vector3(), + _vC = new THREE.Vector3(), + + _vector3 = new THREE.Vector3(), + _vector4 = new THREE.Vector4(), + + _clipBox = new THREE.Box3( new THREE.Vector3( -1, -1, -1 ), new THREE.Vector3( 1, 1, 1 ) ), + _boundingBox = new THREE.Box3(), + _points3 = new Array( 3 ), + _points4 = new Array( 4 ), + + _viewMatrix = new THREE.Matrix4(), + _viewProjectionMatrix = new THREE.Matrix4(), + + _modelMatrix, + _modelViewProjectionMatrix = new THREE.Matrix4(), + + _normalMatrix = new THREE.Matrix3(), + + _frustum = new THREE.Frustum(), + + _clippedVertex1PositionScreen = new THREE.Vector4(), + _clippedVertex2PositionScreen = new THREE.Vector4(); + + this.projectVector = function ( vector, camera ) { + + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + + _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + + return vector.applyProjection( _viewProjectionMatrix ); + + }; + + this.unprojectVector = function () { + + var projectionMatrixInverse = new THREE.Matrix4(); + + return function ( vector, camera ) { + + projectionMatrixInverse.getInverse( camera.projectionMatrix ); + _viewProjectionMatrix.multiplyMatrices( camera.matrixWorld, projectionMatrixInverse ); + + return vector.applyProjection( _viewProjectionMatrix ); + + }; + + }(); + + this.pickingRay = function ( vector, camera ) { + + // set two vectors with opposing z values + vector.z = -1.0; + var end = new THREE.Vector3( vector.x, vector.y, 1.0 ); + + this.unprojectVector( vector, camera ); + this.unprojectVector( end, camera ); + + // find direction from vector to end + end.sub( vector ).normalize(); + + return new THREE.Raycaster( vector, end ); + + }; + + var projectObject = function ( object ) { + + if ( object.visible === false ) return; + + if ( object instanceof THREE.Light ) { + + _renderData.lights.push( object ); + + } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) { + + if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) { + + _object = getNextObjectInPool(); + _object.id = object.id; + _object.object = object; + + if ( object.renderDepth !== null ) { + + _object.z = object.renderDepth; + + } else { + + _vector3.setFromMatrixPosition( object.matrixWorld ); + _vector3.applyProjection( _viewProjectionMatrix ); + _object.z = _vector3.z; + + } + + _renderData.objects.push( _object ); + + } + + } + + for ( var i = 0, l = object.children.length; i < l; i ++ ) { + + projectObject( object.children[ i ] ); + + } + + }; + + var projectGraph = function ( root, sortObjects ) { + + _objectCount = 0; + + _renderData.objects.length = 0; + _renderData.lights.length = 0; + + projectObject( root ); + + if ( sortObjects === true ) { + + _renderData.objects.sort( painterSort ); + + } + + }; + + var RenderList = function () { + + var normals = []; + + var object = null; + var normalMatrix = new THREE.Matrix3(); + + var setObject = function ( value ) { + + object = value; + normalMatrix.getNormalMatrix( object.matrixWorld ); + + normals.length = 0; + + }; + + var projectVertex = function ( vertex ) { + + var position = vertex.position; + var positionWorld = vertex.positionWorld; + var positionScreen = vertex.positionScreen; + + positionWorld.copy( position ).applyMatrix4( _modelMatrix ); + positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix ); + + var invW = 1 / positionScreen.w; + + positionScreen.x *= invW; + positionScreen.y *= invW; + positionScreen.z *= invW; + + vertex.visible = positionScreen.x >= -1 && positionScreen.x <= 1 && + positionScreen.y >= -1 && positionScreen.y <= 1 && + positionScreen.z >= -1 && positionScreen.z <= 1; + + }; + + var pushVertex = function ( x, y, z ) { + + _vertex = getNextVertexInPool(); + _vertex.position.set( x, y, z ); + + projectVertex( _vertex ); + + }; + + var pushNormal = function ( x, y, z ) { + + normals.push( x, y, z ); + + }; + + var checkTriangleVisibility = function ( v1, v2, v3 ) { + + _points3[ 0 ] = v1.positionScreen; + _points3[ 1 ] = v2.positionScreen; + _points3[ 2 ] = v3.positionScreen; + + if ( v1.visible === true || v2.visible === true || v3.visible === true || + _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) ) ) { + + return ( ( v3.positionScreen.x - v1.positionScreen.x ) * + ( v2.positionScreen.y - v1.positionScreen.y ) - + ( v3.positionScreen.y - v1.positionScreen.y ) * + ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0; + + } + + return false; + + }; + + var pushLine = function ( a, b ) { + + var v1 = _vertexPool[ a ]; + var v2 = _vertexPool[ b ]; + + _line = getNextLineInPool(); + + _line.id = object.id; + _line.v1.copy( v1 ); + _line.v2.copy( v2 ); + _line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2; + + _line.material = object.material; + + _renderData.elements.push( _line ); + + }; + + var pushTriangle = function ( a, b, c ) { + + var v1 = _vertexPool[ a ]; + var v2 = _vertexPool[ b ]; + var v3 = _vertexPool[ c ]; + + if ( checkTriangleVisibility( v1, v2, v3 ) === true ) { + + _face = getNextFaceInPool(); + + _face.id = object.id; + _face.v1.copy( v1 ); + _face.v2.copy( v2 ); + _face.v3.copy( v3 ); + _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; + + for ( var i = 0; i < 3; i ++ ) { + + var offset = arguments[ i ] * 3; + var normal = _face.vertexNormalsModel[ i ]; + + normal.set( normals[ offset + 0 ], normals[ offset + 1 ], normals[ offset + 2 ] ); + normal.applyMatrix3( normalMatrix ).normalize(); + + } + + _face.vertexNormalsLength = 3; + + _face.material = object.material; + + _renderData.elements.push( _face ); + + } + + }; + + return { + setObject: setObject, + projectVertex: projectVertex, + checkTriangleVisibility: checkTriangleVisibility, + pushVertex: pushVertex, + pushNormal: pushNormal, + pushLine: pushLine, + pushTriangle: pushTriangle + } + + }; + + var renderList = new RenderList(); + + this.projectScene = function ( scene, camera, sortObjects, sortElements ) { + + var object, geometry, vertices, faces, face, faceVertexNormals, faceVertexUvs, uvs, + isFaceMaterial, objectMaterials; + + _faceCount = 0; + _lineCount = 0; + _spriteCount = 0; + + _renderData.elements.length = 0; + + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + if ( camera.parent === undefined ) camera.updateMatrixWorld(); + + _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) ); + _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix ); + + _frustum.setFromMatrix( _viewProjectionMatrix ); + + projectGraph( scene, sortObjects ); + + for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) { + + object = _renderData.objects[ o ].object; + geometry = object.geometry; + + renderList.setObject( object ); + + _modelMatrix = object.matrixWorld; + + _vertexCount = 0; + + if ( object instanceof THREE.Mesh ) { + + if ( geometry instanceof THREE.BufferGeometry ) { + + var attributes = geometry.attributes; + var offsets = geometry.offsets; + + if ( attributes.position === undefined ) continue; + + var positions = attributes.position.array; + + for ( var i = 0, l = positions.length; i < l; i += 3 ) { + + renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + + } + + var normals = attributes.normal.array; + + for ( var i = 0, l = normals.length; i < l; i += 3 ) { + + renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ); + + } + + if ( attributes.index !== undefined ) { + + var indices = attributes.index.array; + + if ( offsets.length > 0 ) { + + for ( var o = 0; o < offsets.length; o ++ ) { + + var offset = offsets[ o ]; + var index = offset.index; + + for ( var i = offset.start, l = offset.start + offset.count; i < l; i += 3 ) { + + renderList.pushTriangle( indices[ i ] + index, indices[ i + 1 ] + index, indices[ i + 2 ] + index ); + + } + + } + + } else { + + for ( var i = 0, l = indices.length; i < l; i += 3 ) { + + renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); + + } + + } + + } else { + + for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) { + + renderList.pushTriangle( i, i + 1, i + 2 ); + + } + + } + + } else if ( geometry instanceof THREE.Geometry ) { + + vertices = geometry.vertices; + faces = geometry.faces; + faceVertexUvs = geometry.faceVertexUvs; + + _normalMatrix.getNormalMatrix( _modelMatrix ); + + isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; + objectMaterials = isFaceMaterial === true ? object.material : null; + + for ( var v = 0, vl = vertices.length; v < vl; v ++ ) { + + var vertex = vertices[ v ]; + renderList.pushVertex( vertex.x, vertex.y, vertex.z ); + + } + + for ( var f = 0, fl = faces.length; f < fl; f ++ ) { + + face = faces[ f ]; + + var material = isFaceMaterial === true + ? objectMaterials.materials[ face.materialIndex ] + : object.material; + + if ( material === undefined ) continue; + + var side = material.side; + + var v1 = _vertexPool[ face.a ]; + var v2 = _vertexPool[ face.b ]; + var v3 = _vertexPool[ face.c ]; + + if ( material.morphTargets === true ) { + + var morphTargets = geometry.morphTargets; + var morphInfluences = object.morphTargetInfluences; + + var v1p = v1.position; + var v2p = v2.position; + var v3p = v3.position; + + _vA.set( 0, 0, 0 ); + _vB.set( 0, 0, 0 ); + _vC.set( 0, 0, 0 ); + + for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { + + var influence = morphInfluences[ t ]; + + if ( influence === 0 ) continue; + + var targets = morphTargets[ t ].vertices; + + _vA.x += ( targets[ face.a ].x - v1p.x ) * influence; + _vA.y += ( targets[ face.a ].y - v1p.y ) * influence; + _vA.z += ( targets[ face.a ].z - v1p.z ) * influence; + + _vB.x += ( targets[ face.b ].x - v2p.x ) * influence; + _vB.y += ( targets[ face.b ].y - v2p.y ) * influence; + _vB.z += ( targets[ face.b ].z - v2p.z ) * influence; + + _vC.x += ( targets[ face.c ].x - v3p.x ) * influence; + _vC.y += ( targets[ face.c ].y - v3p.y ) * influence; + _vC.z += ( targets[ face.c ].z - v3p.z ) * influence; + + } + + v1.position.add( _vA ); + v2.position.add( _vB ); + v3.position.add( _vC ); + + renderList.projectVertex( v1 ); + renderList.projectVertex( v2 ); + renderList.projectVertex( v3 ); + + } + + var visible = renderList.checkTriangleVisibility( v1, v2, v3 ); + + if ( ( visible === false && side === THREE.FrontSide ) || + ( visible === true && side === THREE.BackSide ) ) continue; + + _face = getNextFaceInPool(); + + _face.id = object.id; + _face.v1.copy( v1 ); + _face.v2.copy( v2 ); + _face.v3.copy( v3 ); + + _face.normalModel.copy( face.normal ); + + if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { + + _face.normalModel.negate(); + + } + + _face.normalModel.applyMatrix3( _normalMatrix ).normalize(); + + _face.centroidModel.copy( face.centroid ).applyMatrix4( _modelMatrix ); + + faceVertexNormals = face.vertexNormals; + + for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) { + + var normalModel = _face.vertexNormalsModel[ n ]; + normalModel.copy( faceVertexNormals[ n ] ); + + if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { + + normalModel.negate(); + + } + + normalModel.applyMatrix3( _normalMatrix ).normalize(); + + } + + _face.vertexNormalsLength = faceVertexNormals.length; + + for ( var c = 0, cl = Math.min( faceVertexUvs.length, 3 ); c < cl; c ++ ) { + + uvs = faceVertexUvs[ c ][ f ]; + + if ( uvs === undefined ) continue; + + for ( var u = 0, ul = uvs.length; u < ul; u ++ ) { + + _face.uvs[ c ][ u ] = uvs[ u ]; + + } + + } + + _face.color = face.color; + _face.material = material; + + _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; + + _renderData.elements.push( _face ); + + } + + } + + } else if ( object instanceof THREE.Line ) { + + if ( geometry instanceof THREE.BufferGeometry ) { + + var attributes = geometry.attributes; + + if ( attributes.position !== undefined ) { + + var positions = attributes.position.array; + + for ( var i = 0, l = positions.length; i < l; i += 3 ) { + + renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + + } + + if ( attributes.index !== undefined ) { + + var indices = attributes.index.array; + + for ( var i = 0, l = indices.length; i < l; i += 2 ) { + + renderList.pushLine( indices[ i ], indices[ i + 1 ] ); + + } + + } else { + + for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i ++ ) { + + renderList.pushLine( i, i + 1 ); + + } + + } + + } + + } else if ( geometry instanceof THREE.Geometry ) { + + _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); + + vertices = object.geometry.vertices; + + if ( vertices.length === 0 ) continue; + + v1 = getNextVertexInPool(); + v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix ); + + // Handle LineStrip and LinePieces + var step = object.type === THREE.LinePieces ? 2 : 1; + + for ( var v = 1, vl = vertices.length; v < vl; v ++ ) { + + v1 = getNextVertexInPool(); + v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix ); + + if ( ( v + 1 ) % step > 0 ) continue; + + v2 = _vertexPool[ _vertexCount - 2 ]; + + _clippedVertex1PositionScreen.copy( v1.positionScreen ); + _clippedVertex2PositionScreen.copy( v2.positionScreen ); + + if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) { + + // Perform the perspective divide + _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w ); + _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w ); + + _line = getNextLineInPool(); + + _line.id = object.id; + _line.v1.positionScreen.copy( _clippedVertex1PositionScreen ); + _line.v2.positionScreen.copy( _clippedVertex2PositionScreen ); + + _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); + + _line.material = object.material; + + if ( object.material.vertexColors === THREE.VertexColors ) { + + _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] ); + _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] ); + + } + + _renderData.elements.push( _line ); + + } + + } + + } + + } else if ( object instanceof THREE.Sprite ) { + + _vector4.set( _modelMatrix.elements[12], _modelMatrix.elements[13], _modelMatrix.elements[14], 1 ); + _vector4.applyMatrix4( _viewProjectionMatrix ); + + var invW = 1 / _vector4.w; + + _vector4.z *= invW; + + if ( _vector4.z >= -1 && _vector4.z <= 1 ) { + + _sprite = getNextSpriteInPool(); + _sprite.id = object.id; + _sprite.x = _vector4.x * invW; + _sprite.y = _vector4.y * invW; + _sprite.z = _vector4.z; + _sprite.object = object; + + _sprite.rotation = object.rotation; + + _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[0] ) / ( _vector4.w + camera.projectionMatrix.elements[12] ) ); + _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[5] ) / ( _vector4.w + camera.projectionMatrix.elements[13] ) ); + + _sprite.material = object.material; + + _renderData.elements.push( _sprite ); + + } + + } + + } + + if ( sortElements === true ) _renderData.elements.sort( painterSort ); + + return _renderData; + + }; + + // Pools + + function getNextObjectInPool() { + + if ( _objectCount === _objectPoolLength ) { + + var object = new THREE.RenderableObject(); + _objectPool.push( object ); + _objectPoolLength ++; + _objectCount ++; + return object; + + } + + return _objectPool[ _objectCount ++ ]; + + } + + function getNextVertexInPool() { + + if ( _vertexCount === _vertexPoolLength ) { + + var vertex = new THREE.RenderableVertex(); + _vertexPool.push( vertex ); + _vertexPoolLength ++; + _vertexCount ++; + return vertex; + + } + + return _vertexPool[ _vertexCount ++ ]; + + } + + function getNextFaceInPool() { + + if ( _faceCount === _facePoolLength ) { + + var face = new THREE.RenderableFace(); + _facePool.push( face ); + _facePoolLength ++; + _faceCount ++; + return face; + + } + + return _facePool[ _faceCount ++ ]; + + + } + + function getNextLineInPool() { + + if ( _lineCount === _linePoolLength ) { + + var line = new THREE.RenderableLine(); + _linePool.push( line ); + _linePoolLength ++; + _lineCount ++ + return line; + + } + + return _linePool[ _lineCount ++ ]; + + } + + function getNextSpriteInPool() { + + if ( _spriteCount === _spritePoolLength ) { + + var sprite = new THREE.RenderableSprite(); + _spritePool.push( sprite ); + _spritePoolLength ++; + _spriteCount ++ + return sprite; + + } + + return _spritePool[ _spriteCount ++ ]; + + } + + // + + function painterSort( a, b ) { + + if ( a.z !== b.z ) { + + return b.z - a.z; + + } else if ( a.id !== b.id ) { + + return a.id - b.id; + + } else { + + return 0; + + } + + } + + function clipLine( s1, s2 ) { + + var alpha1 = 0, alpha2 = 1, + + // Calculate the boundary coordinate of each vertex for the near and far clip planes, + // Z = -1 and Z = +1, respectively. + bc1near = s1.z + s1.w, + bc2near = s2.z + s2.w, + bc1far = - s1.z + s1.w, + bc2far = - s2.z + s2.w; + + if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { + + // Both vertices lie entirely within all clip planes. + return true; + + } else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) { + + // Both vertices lie entirely outside one of the clip planes. + return false; + + } else { + + // The line segment spans at least one clip plane. + + if ( bc1near < 0 ) { + + // v1 lies outside the near plane, v2 inside + alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) ); + + } else if ( bc2near < 0 ) { + + // v2 lies outside the near plane, v1 inside + alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) ); + + } + + if ( bc1far < 0 ) { + + // v1 lies outside the far plane, v2 inside + alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) ); + + } else if ( bc2far < 0 ) { + + // v2 lies outside the far plane, v2 inside + alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) ); + + } + + if ( alpha2 < alpha1 ) { + + // The line segment spans two boundaries, but is outside both of them. + // (This can't happen when we're only clipping against just near/far but good + // to leave the check here for future usage if other clip planes are added.) + return false; + + } else { + + // Update the s1 and s2 vertices to match the clipped line segment. + s1.lerp( s2, alpha1 ); + s2.lerp( s1, 1 - alpha2 ); + + return true; + + } + + } + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) { + + this.a = a; + this.b = b; + this.c = c; + + this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); + this.vertexNormals = normal instanceof Array ? normal : [ ]; + + this.color = color instanceof THREE.Color ? color : new THREE.Color(); + this.vertexColors = color instanceof Array ? color : []; + + this.vertexTangents = []; + + this.materialIndex = materialIndex !== undefined ? materialIndex : 0; + + this.centroid = new THREE.Vector3(); + +}; + +THREE.Face3.prototype = { + + constructor: THREE.Face3, + + clone: function () { + + var face = new THREE.Face3( this.a, this.b, this.c ); + + face.normal.copy( this.normal ); + face.color.copy( this.color ); + face.centroid.copy( this.centroid ); + + face.materialIndex = this.materialIndex; + + var i, il; + for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone(); + for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone(); + for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone(); + + return face; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { + + THREE.onwarning( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.') + + return new THREE.Face3( a, b, c, normal, color, materialIndex ); + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.BufferGeometry = function () { + + this.id = THREE.GeometryIdCount ++; + this.uuid = THREE.Math.generateUUID(); + this.className = "BufferGeometry"; + this.name = ''; + + // attributes + + this.attributes = {}; + + // offsets for chunks when using indexed elements + + this.offsets = []; + + // boundings + + this.boundingBox = null; + this.boundingSphere = null; + +}; + +THREE.BufferGeometry.prototype = { + + constructor: THREE.BufferGeometry, + + addAttribute: function ( name, type, numItems, itemSize ) { + + this.attributes[ name ] = { + + array: new type( numItems * itemSize ), + itemSize: itemSize + + }; + + return this.attributes[ name ]; + + }, + + applyMatrix: function ( matrix ) { + + var position = this.attributes.position; + + if ( position !== undefined ) { + + matrix.multiplyVector3Array( position.array ); + position.needsUpdate = true; + + } + + var normal = this.attributes.normal; + + if ( normal !== undefined ) { + + var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); + + normalMatrix.multiplyVector3Array( normal.array ); + normal.needsUpdate = true; + + } + + }, + + computeBoundingBox: function () { + + if ( this.boundingBox === null ) { + + this.boundingBox = new THREE.Box3(); + + } + + var positions = this.attributes[ "position" ].array; + + if ( positions ) { + + var bb = this.boundingBox; + + if( positions.length >= 3 ) { + bb.min.x = bb.max.x = positions[ 0 ]; + bb.min.y = bb.max.y = positions[ 1 ]; + bb.min.z = bb.max.z = positions[ 2 ]; + } + + for ( var i = 3, il = positions.length; i < il; i += 3 ) { + + var x = positions[ i ]; + var y = positions[ i + 1 ]; + var z = positions[ i + 2 ]; + + // bounding box + + if ( x < bb.min.x ) { + + bb.min.x = x; + + } else if ( x > bb.max.x ) { + + bb.max.x = x; + + } + + if ( y < bb.min.y ) { + + bb.min.y = y; + + } else if ( y > bb.max.y ) { + + bb.max.y = y; + + } + + if ( z < bb.min.z ) { + + bb.min.z = z; + + } else if ( z > bb.max.z ) { + + bb.max.z = z; + + } + + } + + } + + if ( positions === undefined || positions.length === 0 ) { + + this.boundingBox.min.set( 0, 0, 0 ); + this.boundingBox.max.set( 0, 0, 0 ); + + } + + }, + + computeBoundingSphere: function () { + + var box = new THREE.Box3(); + var vector = new THREE.Vector3(); + + return function () { + + if ( this.boundingSphere === null ) { + + this.boundingSphere = new THREE.Sphere(); + + } + + var positions = this.attributes[ "position" ].array; + + if ( positions ) { + + box.makeEmpty(); + + var center = this.boundingSphere.center; + + for ( var i = 0, il = positions.length; i < il; i += 3 ) { + + vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + box.addPoint( vector ); + + } + + box.center( center ); + + var maxRadiusSq = 0; + + for ( var i = 0, il = positions.length; i < il; i += 3 ) { + + vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); + + } + + this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); + + } + + } + + }(), + + computeVertexNormals: function () { + + if ( this.attributes[ "position" ] ) { + + var i, il; + var j, jl; + + var nVertexElements = this.attributes[ "position" ].array.length; + + if ( this.attributes[ "normal" ] === undefined ) { + + this.attributes[ "normal" ] = { + + itemSize: 3, + array: new Float32Array( nVertexElements ) + + }; + + } else { + + // reset existing normals to zero + + for ( i = 0, il = this.attributes[ "normal" ].array.length; i < il; i ++ ) { + + this.attributes[ "normal" ].array[ i ] = 0; + + } + + } + + var positions = this.attributes[ "position" ].array; + var normals = this.attributes[ "normal" ].array; + + var vA, vB, vC, x, y, z, + + pA = new THREE.Vector3(), + pB = new THREE.Vector3(), + pC = new THREE.Vector3(), + + cb = new THREE.Vector3(), + ab = new THREE.Vector3(); + + // indexed elements + + if ( this.attributes[ "index" ] ) { + + var indices = this.attributes[ "index" ].array; + + var offsets = this.offsets; + + for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + + var start = offsets[ j ].start; + var count = offsets[ j ].count; + var index = offsets[ j ].index; + + for ( i = start, il = start + count; i < il; i += 3 ) { + + vA = index + indices[ i ]; + vB = index + indices[ i + 1 ]; + vC = index + indices[ i + 2 ]; + + x = positions[ vA * 3 ]; + y = positions[ vA * 3 + 1 ]; + z = positions[ vA * 3 + 2 ]; + pA.set( x, y, z ); + + x = positions[ vB * 3 ]; + y = positions[ vB * 3 + 1 ]; + z = positions[ vB * 3 + 2 ]; + pB.set( x, y, z ); + + x = positions[ vC * 3 ]; + y = positions[ vC * 3 + 1 ]; + z = positions[ vC * 3 + 2 ]; + pC.set( x, y, z ); + + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); + + normals[ vA * 3 ] += cb.x; + normals[ vA * 3 + 1 ] += cb.y; + normals[ vA * 3 + 2 ] += cb.z; + + normals[ vB * 3 ] += cb.x; + normals[ vB * 3 + 1 ] += cb.y; + normals[ vB * 3 + 2 ] += cb.z; + + normals[ vC * 3 ] += cb.x; + normals[ vC * 3 + 1 ] += cb.y; + normals[ vC * 3 + 2 ] += cb.z; + + } + + } + + // non-indexed elements (unconnected triangle soup) + + } else { + + for ( i = 0, il = positions.length; i < il; i += 9 ) { + + x = positions[ i ]; + y = positions[ i + 1 ]; + z = positions[ i + 2 ]; + pA.set( x, y, z ); + + x = positions[ i + 3 ]; + y = positions[ i + 4 ]; + z = positions[ i + 5 ]; + pB.set( x, y, z ); + + x = positions[ i + 6 ]; + y = positions[ i + 7 ]; + z = positions[ i + 8 ]; + pC.set( x, y, z ); + + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); + + normals[ i ] = cb.x; + normals[ i + 1 ] = cb.y; + normals[ i + 2 ] = cb.z; + + normals[ i + 3 ] = cb.x; + normals[ i + 4 ] = cb.y; + normals[ i + 5 ] = cb.z; + + normals[ i + 6 ] = cb.x; + normals[ i + 7 ] = cb.y; + normals[ i + 8 ] = cb.z; + + } + + } + + this.normalizeNormals(); + + this.normalsNeedUpdate = true; + + } + + }, + + normalizeNormals: function () { + + var normals = this.attributes[ "normal" ].array; + + var x, y, z, n; + + for ( var i = 0, il = normals.length; i < il; i += 3 ) { + + x = normals[ i ]; + y = normals[ i + 1 ]; + z = normals[ i + 2 ]; + + n = 1.0 / Math.sqrt( x * x + y * y + z * z ); + + normals[ i ] *= n; + normals[ i + 1 ] *= n; + normals[ i + 2 ] *= n; + + } + + }, + + computeTangents: function () { + + // based on http://www.terathon.com/code/tangent.html + // (per vertex tangents) + + if ( this.attributes[ "index" ] === undefined || + this.attributes[ "position" ] === undefined || + this.attributes[ "normal" ] === undefined || + this.attributes[ "uv" ] === undefined ) { + + THREE.onwarning( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" ); + return; + + } + + var indices = this.attributes[ "index" ].array; + var positions = this.attributes[ "position" ].array; + var normals = this.attributes[ "normal" ].array; + var uvs = this.attributes[ "uv" ].array; + + var nVertices = positions.length / 3; + + if ( this.attributes[ "tangent" ] === undefined ) { + + var nTangentElements = 4 * nVertices; + + this.attributes[ "tangent" ] = { + + itemSize: 4, + array: new Float32Array( nTangentElements ) + + }; + + } + + var tangents = this.attributes[ "tangent" ].array; + + var tan1 = [], tan2 = []; + + for ( var k = 0; k < nVertices; k ++ ) { + + tan1[ k ] = new THREE.Vector3(); + tan2[ k ] = new THREE.Vector3(); + + } + + var xA, yA, zA, + xB, yB, zB, + xC, yC, zC, + + uA, vA, + uB, vB, + uC, vC, + + x1, x2, y1, y2, z1, z2, + s1, s2, t1, t2, r; + + var sdir = new THREE.Vector3(), tdir = new THREE.Vector3(); + + function handleTriangle( a, b, c ) { + + xA = positions[ a * 3 ]; + yA = positions[ a * 3 + 1 ]; + zA = positions[ a * 3 + 2 ]; + + xB = positions[ b * 3 ]; + yB = positions[ b * 3 + 1 ]; + zB = positions[ b * 3 + 2 ]; + + xC = positions[ c * 3 ]; + yC = positions[ c * 3 + 1 ]; + zC = positions[ c * 3 + 2 ]; + + uA = uvs[ a * 2 ]; + vA = uvs[ a * 2 + 1 ]; + + uB = uvs[ b * 2 ]; + vB = uvs[ b * 2 + 1 ]; + + uC = uvs[ c * 2 ]; + vC = uvs[ c * 2 + 1 ]; + + x1 = xB - xA; + x2 = xC - xA; + + y1 = yB - yA; + y2 = yC - yA; + + z1 = zB - zA; + z2 = zC - zA; + + s1 = uB - uA; + s2 = uC - uA; + + t1 = vB - vA; + t2 = vC - vA; + + r = 1.0 / ( s1 * t2 - s2 * t1 ); + + sdir.set( + ( t2 * x1 - t1 * x2 ) * r, + ( t2 * y1 - t1 * y2 ) * r, + ( t2 * z1 - t1 * z2 ) * r + ); + + tdir.set( + ( s1 * x2 - s2 * x1 ) * r, + ( s1 * y2 - s2 * y1 ) * r, + ( s1 * z2 - s2 * z1 ) * r + ); + + tan1[ a ].add( sdir ); + tan1[ b ].add( sdir ); + tan1[ c ].add( sdir ); + + tan2[ a ].add( tdir ); + tan2[ b ].add( tdir ); + tan2[ c ].add( tdir ); + + } + + var i, il; + var j, jl; + var iA, iB, iC; + + var offsets = this.offsets; + + for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + + var start = offsets[ j ].start; + var count = offsets[ j ].count; + var index = offsets[ j ].index; + + for ( i = start, il = start + count; i < il; i += 3 ) { + + iA = index + indices[ i ]; + iB = index + indices[ i + 1 ]; + iC = index + indices[ i + 2 ]; + + handleTriangle( iA, iB, iC ); + + } + + } + + var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(); + var n = new THREE.Vector3(), n2 = new THREE.Vector3(); + var w, t, test; + + function handleVertex( v ) { + + n.x = normals[ v * 3 ]; + n.y = normals[ v * 3 + 1 ]; + n.z = normals[ v * 3 + 2 ]; + + n2.copy( n ); + + t = tan1[ v ]; + + // Gram-Schmidt orthogonalize + + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + + // Calculate handedness + + tmp2.crossVectors( n2, t ); + test = tmp2.dot( tan2[ v ] ); + w = ( test < 0.0 ) ? -1.0 : 1.0; + + tangents[ v * 4 ] = tmp.x; + tangents[ v * 4 + 1 ] = tmp.y; + tangents[ v * 4 + 2 ] = tmp.z; + tangents[ v * 4 + 3 ] = w; + + } + + for ( j = 0, jl = offsets.length; j < jl; ++ j ) { + + var start = offsets[ j ].start; + var count = offsets[ j ].count; + var index = offsets[ j ].index; + + for ( i = start, il = start + count; i < il; i += 3 ) { + + iA = index + indices[ i ]; + iB = index + indices[ i + 1 ]; + iC = index + indices[ i + 2 ]; + + handleVertex( iA ); + handleVertex( iB ); + handleVertex( iC ); + + } + + } + + }, + + /* + computeOffsets + Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices. + This method will effectively rewrite the index buffer and remap all attributes to match the new indices. + WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets. + indexBufferSize - Defaults to 65535, but allows for larger or smaller chunks. + */ + computeOffsets: function(indexBufferSize) { + + var size = indexBufferSize; + if(indexBufferSize === undefined) + size = 65535; //WebGL limits type of index buffer values to 16-bit. + + var s = Date.now(); + + var indices = this.attributes['index'].array; + var vertices = this.attributes['position'].array; + + var verticesCount = (vertices.length/3); + var facesCount = (indices.length/3); + + /* + console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length); + console.log("Faces to process: "+(indices.length/3)); + console.log("Reordering "+verticesCount+" vertices."); + */ + + var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers + var indexPtr = 0; + var vertexPtr = 0; + + var offsets = [ { start:0, count:0, index:0 } ]; + var offset = offsets[0]; + + var duplicatedVertices = 0; + var newVerticeMaps = 0; + var faceVertices = new Int32Array(6); + var vertexMap = new Int32Array( vertices.length ); + var revVertexMap = new Int32Array( vertices.length ); + for(var j = 0; j < vertices.length; j++) { vertexMap[j] = -1; revVertexMap[j] = -1; } + + /* + Traverse every face and reorder vertices in the proper offsets of 65k. + We can have more than 65k entries in the index buffer per offset, but only reference 65k values. + */ + for(var findex = 0; findex < facesCount; findex++) { + newVerticeMaps = 0; + + for(var vo = 0; vo < 3; vo++) { + var vid = indices[ findex*3 + vo ]; + if(vertexMap[vid] == -1) { + //Unmapped vertice + faceVertices[vo*2] = vid; + faceVertices[vo*2+1] = -1; + newVerticeMaps++; + } else if(vertexMap[vid] < offset.index) { + //Reused vertices from previous block (duplicate) + faceVertices[vo*2] = vid; + faceVertices[vo*2+1] = -1; + duplicatedVertices++; + } else { + //Reused vertice in the current block + faceVertices[vo*2] = vid; + faceVertices[vo*2+1] = vertexMap[vid]; + } + } + + var faceMax = vertexPtr + newVerticeMaps; + if(faceMax > (offset.index + size)) { + var new_offset = { start:indexPtr, count:0, index:vertexPtr }; + offsets.push(new_offset); + offset = new_offset; + + //Re-evaluate reused vertices in light of new offset. + for(var v = 0; v < 6; v+=2) { + var new_vid = faceVertices[v+1]; + if(new_vid > -1 && new_vid < offset.index) + faceVertices[v+1] = -1; + } + } + + //Reindex the face. + for(var v = 0; v < 6; v+=2) { + var vid = faceVertices[v]; + var new_vid = faceVertices[v+1]; + + if(new_vid === -1) + new_vid = vertexPtr++; + + vertexMap[vid] = new_vid; + revVertexMap[new_vid] = vid; + sortedIndices[indexPtr++] = new_vid - offset.index; //XXX overflows at 16bit + offset.count++; + } + } + + /* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */ + this.reorderBuffers(sortedIndices, revVertexMap, vertexPtr); + this.offsets = offsets; + + /* + var orderTime = Date.now(); + console.log("Reorder time: "+(orderTime-s)+"ms"); + console.log("Duplicated "+duplicatedVertices+" vertices."); + console.log("Compute Buffers time: "+(Date.now()-s)+"ms"); + console.log("Draw offsets: "+offsets.length); + */ + + return offsets; + }, + + /* + reoderBuffers: + Reorder attributes based on a new indexBuffer and indexMap. + indexBuffer - Uint16Array of the new ordered indices. + indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex. + vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack). + */ + reorderBuffers: function(indexBuffer, indexMap, vertexCount) { + + /* Create a copy of all attributes for reordering. */ + var sortedAttributes = {}; + var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; + for( var attr in this.attributes ) { + if(attr == 'index') + continue; + var sourceArray = this.attributes[attr].array; + for ( var i = 0, il = types.length; i < il; i++ ) { + var type = types[i]; + if (sourceArray instanceof type) { + sortedAttributes[attr] = new type( this.attributes[attr].itemSize * vertexCount ); + break; + } + } + } + + /* Move attribute positions based on the new index map */ + for(var new_vid = 0; new_vid < vertexCount; new_vid++) { + var vid = indexMap[new_vid]; + for ( var attr in this.attributes ) { + if(attr == 'index') + continue; + var attrArray = this.attributes[attr].array; + var attrSize = this.attributes[attr].itemSize; + var sortedAttr = sortedAttributes[attr]; + for(var k = 0; k < attrSize; k++) + sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ]; + } + } + + /* Carry the new sorted buffers locally */ + this.attributes['index'].array = indexBuffer; + for ( var attr in this.attributes ) { + if(attr == 'index') + continue; + this.attributes[attr].array = sortedAttributes[attr]; + this.attributes[attr].numItems = this.attributes[attr].itemSize * vertexCount; + } + }, + + clone: function () { + + var geometry = new THREE.BufferGeometry(); + + var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; + + for ( var attr in this.attributes ) { + + var sourceAttr = this.attributes[ attr ]; + var sourceArray = sourceAttr.array; + + var attribute = { + + itemSize: sourceAttr.itemSize, + array: null + + }; + + for ( var i = 0, il = types.length; i < il; i ++ ) { + + var type = types[ i ]; + + if ( sourceArray instanceof type ) { + + attribute.array = new type( sourceArray ); + break; + + } + + } + + geometry.attributes[ attr ] = attribute; + + } + + for ( var i = 0, il = this.offsets.length; i < il; i ++ ) { + + var offset = this.offsets[ i ]; + + geometry.offsets.push( { + + start: offset.start, + index: offset.index, + count: offset.count + + } ); + + } + + return geometry; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype ); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author kile / http://kile.stravaganza.org/ + * @author alteredq / http://alteredqualia.com/ + * @author mikael emtinger / http://gomo.se/ + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author bhouston / http://exocortex.com + */ + +THREE.Geometry = function () { + + this.id = THREE.GeometryIdCount ++; + this.uuid = THREE.Math.generateUUID(); + this.className = "Geometry"; + + this.name = ''; + + this.vertices = []; + this.colors = []; // one-to-one vertex colors, used in ParticleSystem and Line + + this.faces = []; + + this.faceVertexUvs = [[]]; + + this.morphTargets = []; + this.morphColors = []; + this.morphNormals = []; + + this.skinWeights = []; + this.skinIndices = []; + + this.lineDistances = []; + + this.boundingBox = null; + this.boundingSphere = null; + + this.hasTangents = true; + + this.dynamic = true; // the intermediate typed arrays will be deleted when set to false + + // update flags + + this.verticesNeedUpdate = false; + this.elementsNeedUpdate = false; + this.uvsNeedUpdate = false; + this.normalsNeedUpdate = false; + this.tangentsNeedUpdate = false; + this.colorsNeedUpdate = false; + this.lineDistancesNeedUpdate = false; + + this.buffersNeedUpdate = false; + +}; + +THREE.Geometry.prototype = { + + constructor: THREE.Geometry, + + applyMatrix: function ( matrix ) { + + var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); + + for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { + + var vertex = this.vertices[ i ]; + vertex.applyMatrix4( matrix ); + + } + + for ( var i = 0, il = this.faces.length; i < il; i ++ ) { + + var face = this.faces[ i ]; + face.normal.applyMatrix3( normalMatrix ).normalize(); + + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + + face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); + + } + + face.centroid.applyMatrix4( matrix ); + + } + + if ( this.boundingBox instanceof THREE.Box3 ) { + + this.computeBoundingBox(); + + } + + if ( this.boundingSphere instanceof THREE.Sphere ) { + + this.computeBoundingSphere(); + + } + + }, + + computeCentroids: function () { + + var f, fl, face; + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + face.centroid.set( 0, 0, 0 ); + + face.centroid.add( this.vertices[ face.a ] ); + face.centroid.add( this.vertices[ face.b ] ); + face.centroid.add( this.vertices[ face.c ] ); + face.centroid.divideScalar( 3 ); + + } + + }, + + computeFaceNormals: function () { + + var cb = new THREE.Vector3(), ab = new THREE.Vector3(); + + for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { + + var face = this.faces[ f ]; + + var vA = this.vertices[ face.a ]; + var vB = this.vertices[ face.b ]; + var vC = this.vertices[ face.c ]; + + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); + + cb.normalize(); + + face.normal.copy( cb ); + + } + + }, + + computeVertexNormals: function ( areaWeighted ) { + + var v, vl, f, fl, face, vertices; + + vertices = new Array( this.vertices.length ); + + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + + vertices[ v ] = new THREE.Vector3(); + + } + + if ( areaWeighted ) { + + // vertex normals weighted by triangle areas + // http://www.iquilezles.org/www/articles/normals/normals.htm + + var vA, vB, vC, vD; + var cb = new THREE.Vector3(), ab = new THREE.Vector3(), + db = new THREE.Vector3(), dc = new THREE.Vector3(), bc = new THREE.Vector3(); + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + vA = this.vertices[ face.a ]; + vB = this.vertices[ face.b ]; + vC = this.vertices[ face.c ]; + + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); + + vertices[ face.a ].add( cb ); + vertices[ face.b ].add( cb ); + vertices[ face.c ].add( cb ); + + } + + } else { + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + vertices[ face.a ].add( face.normal ); + vertices[ face.b ].add( face.normal ); + vertices[ face.c ].add( face.normal ); + + } + + } + + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + + vertices[ v ].normalize(); + + } + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + face.vertexNormals[ 0 ] = vertices[ face.a ].clone(); + face.vertexNormals[ 1 ] = vertices[ face.b ].clone(); + face.vertexNormals[ 2 ] = vertices[ face.c ].clone(); + + } + + }, + + computeMorphNormals: function () { + + var i, il, f, fl, face; + + // save original normals + // - create temp variables on first access + // otherwise just copy (for faster repeated calls) + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + if ( ! face.__originalFaceNormal ) { + + face.__originalFaceNormal = face.normal.clone(); + + } else { + + face.__originalFaceNormal.copy( face.normal ); + + } + + if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; + + for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { + + if ( ! face.__originalVertexNormals[ i ] ) { + + face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); + + } else { + + face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); + + } + + } + + } + + // use temp geometry to compute face and vertex normals for each morph + + var tmpGeo = new THREE.Geometry(); + tmpGeo.faces = this.faces; + + for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { + + // create on first access + + if ( ! this.morphNormals[ i ] ) { + + this.morphNormals[ i ] = {}; + this.morphNormals[ i ].faceNormals = []; + this.morphNormals[ i ].vertexNormals = []; + + var dstNormalsFace = this.morphNormals[ i ].faceNormals; + var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; + + var faceNormal, vertexNormals; + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + faceNormal = new THREE.Vector3(); + vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() }; + + dstNormalsFace.push( faceNormal ); + dstNormalsVertex.push( vertexNormals ); + + } + + } + + var morphNormals = this.morphNormals[ i ]; + + // set vertices to morph target + + tmpGeo.vertices = this.morphTargets[ i ].vertices; + + // compute morph normals + + tmpGeo.computeFaceNormals(); + tmpGeo.computeVertexNormals(); + + // store morph normals + + var faceNormal, vertexNormals; + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + faceNormal = morphNormals.faceNormals[ f ]; + vertexNormals = morphNormals.vertexNormals[ f ]; + + faceNormal.copy( face.normal ); + + vertexNormals.a.copy( face.vertexNormals[ 0 ] ); + vertexNormals.b.copy( face.vertexNormals[ 1 ] ); + vertexNormals.c.copy( face.vertexNormals[ 2 ] ); + + } + + } + + // restore original normals + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + face.normal = face.__originalFaceNormal; + face.vertexNormals = face.__originalVertexNormals; + + } + + }, + + computeTangents: function () { + + // based on http://www.terathon.com/code/tangent.html + // tangents go to vertices + + var f, fl, v, vl, i, il, vertexIndex, + face, uv, vA, vB, vC, uvA, uvB, uvC, + x1, x2, y1, y2, z1, z2, + s1, s2, t1, t2, r, t, test, + tan1 = [], tan2 = [], + sdir = new THREE.Vector3(), tdir = new THREE.Vector3(), + tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(), + n = new THREE.Vector3(), w; + + for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + + tan1[ v ] = new THREE.Vector3(); + tan2[ v ] = new THREE.Vector3(); + + } + + function handleTriangle( context, a, b, c, ua, ub, uc ) { + + vA = context.vertices[ a ]; + vB = context.vertices[ b ]; + vC = context.vertices[ c ]; + + uvA = uv[ ua ]; + uvB = uv[ ub ]; + uvC = uv[ uc ]; + + x1 = vB.x - vA.x; + x2 = vC.x - vA.x; + y1 = vB.y - vA.y; + y2 = vC.y - vA.y; + z1 = vB.z - vA.z; + z2 = vC.z - vA.z; + + s1 = uvB.x - uvA.x; + s2 = uvC.x - uvA.x; + t1 = uvB.y - uvA.y; + t2 = uvC.y - uvA.y; + + r = 1.0 / ( s1 * t2 - s2 * t1 ); + sdir.set( ( t2 * x1 - t1 * x2 ) * r, + ( t2 * y1 - t1 * y2 ) * r, + ( t2 * z1 - t1 * z2 ) * r ); + tdir.set( ( s1 * x2 - s2 * x1 ) * r, + ( s1 * y2 - s2 * y1 ) * r, + ( s1 * z2 - s2 * z1 ) * r ); + + tan1[ a ].add( sdir ); + tan1[ b ].add( sdir ); + tan1[ c ].add( sdir ); + + tan2[ a ].add( tdir ); + tan2[ b ].add( tdir ); + tan2[ c ].add( tdir ); + + } + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents + + handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 ); + + } + + var faceIndex = [ 'a', 'b', 'c', 'd' ]; + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + + for ( i = 0; i < Math.min( face.vertexNormals.length, 3 ); i++ ) { + + n.copy( face.vertexNormals[ i ] ); + + vertexIndex = face[ faceIndex[ i ] ]; + + t = tan1[ vertexIndex ]; + + // Gram-Schmidt orthogonalize + + tmp.copy( t ); + tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); + + // Calculate handedness + + tmp2.crossVectors( face.vertexNormals[ i ], t ); + test = tmp2.dot( tan2[ vertexIndex ] ); + w = (test < 0.0) ? -1.0 : 1.0; + + face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w ); + + } + + } + + this.hasTangents = true; + + }, + + computeLineDistances: function ( ) { + + var d = 0; + var vertices = this.vertices; + + for ( var i = 0, il = vertices.length; i < il; i ++ ) { + + if ( i > 0 ) { + + d += vertices[ i ].distanceTo( vertices[ i - 1 ] ); + + } + + this.lineDistances[ i ] = d; + + } + + }, + + computeBoundingBox: function () { + + if ( this.boundingBox === null ) { + + this.boundingBox = new THREE.Box3(); + + } + + this.boundingBox.setFromPoints( this.vertices ); + + }, + + computeBoundingSphere: function () { + + if ( this.boundingSphere === null ) { + + this.boundingSphere = new THREE.Sphere(); + + } + + this.boundingSphere.setFromPoints( this.vertices ); + + }, + + /* + * Checks for duplicate vertices with hashmap. + * Duplicated vertices are removed + * and faces' vertices are updated. + */ + + mergeVertices: function () { + + var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique) + var unique = [], changes = []; + + var v, key; + var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001 + var precision = Math.pow( 10, precisionPoints ); + var i,il, face; + var indices, k, j, jl, u; + + for ( i = 0, il = this.vertices.length; i < il; i ++ ) { + + v = this.vertices[ i ]; + key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); + + if ( verticesMap[ key ] === undefined ) { + + verticesMap[ key ] = i; + unique.push( this.vertices[ i ] ); + changes[ i ] = unique.length - 1; + + } else { + + //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); + changes[ i ] = changes[ verticesMap[ key ] ]; + + } + + }; + + + // if faces are completely degenerate after merging vertices, we + // have to remove them from the geometry. + var faceIndicesToRemove = []; + + for( i = 0, il = this.faces.length; i < il; i ++ ) { + + face = this.faces[ i ]; + + face.a = changes[ face.a ]; + face.b = changes[ face.b ]; + face.c = changes[ face.c ]; + + indices = [ face.a, face.b, face.c ]; + + var dupIndex = -1; + + // if any duplicate vertices are found in a Face3 + // we have to remove the face as nothing can be saved + for ( var n = 0; n < 3; n ++ ) { + if ( indices[ n ] == indices[ ( n + 1 ) % 3 ] ) { + + dupIndex = n; + faceIndicesToRemove.push( i ); + break; + + } + } + + } + + for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { + var idx = faceIndicesToRemove[ i ]; + + this.faces.splice( idx, 1 ); + + for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { + + this.faceVertexUvs[ j ].splice( idx, 1 ); + + } + + } + + // Use unique set of vertices + + var diff = this.vertices.length - unique.length; + this.vertices = unique; + return diff; + + }, + + // Geometry splitting + + makeGroups: ( function () { + + var geometryGroupCounter = 0; + + return function ( usesFaceMaterial ) { + + var f, fl, face, materialIndex, + groupHash, hash_map = {}; + + var numMorphTargets = this.morphTargets.length; + var numMorphNormals = this.morphNormals.length; + + this.geometryGroups = {}; + + for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + + face = this.faces[ f ]; + materialIndex = usesFaceMaterial ? face.materialIndex : 0; + + if ( ! ( materialIndex in hash_map ) ) { + + hash_map[ materialIndex ] = { 'hash': materialIndex, 'counter': 0 }; + + } + + groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; + + if ( ! ( groupHash in this.geometryGroups ) ) { + + this.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; + + } + + if ( this.geometryGroups[ groupHash ].vertices + 3 > 65535 ) { + + hash_map[ materialIndex ].counter += 1; + groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; + + if ( ! ( groupHash in this.geometryGroups ) ) { + + this.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; + + } + + } + + this.geometryGroups[ groupHash ].faces3.push( f ); + this.geometryGroups[ groupHash ].vertices += 3; + + } + + this.geometryGroupsList = []; + + for ( var g in this.geometryGroups ) { + + this.geometryGroups[ g ].id = geometryGroupCounter ++; + + this.geometryGroupsList.push( this.geometryGroups[ g ] ); + + } + + }; + + } )(), + + clone: function () { + + var geometry = new THREE.Geometry(); + + var vertices = this.vertices; + + for ( var i = 0, il = vertices.length; i < il; i ++ ) { + + geometry.vertices.push( vertices[ i ].clone() ); + + } + + var faces = this.faces; + + for ( var i = 0, il = faces.length; i < il; i ++ ) { + + geometry.faces.push( faces[ i ].clone() ); + + } + + var uvs = this.faceVertexUvs[ 0 ]; + + for ( var i = 0, il = uvs.length; i < il; i ++ ) { + + var uv = uvs[ i ], uvCopy = []; + + for ( var j = 0, jl = uv.length; j < jl; j ++ ) { + + uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); + + } + + geometry.faceVertexUvs[ 0 ].push( uvCopy ); + + } + + geometry.morphTargets = this.morphTargets.slice( 0 ); + geometry.morphColors = this.morphColors.slice( 0 ); + geometry.morphNormals = this.morphNormals.slice( 0 ); + geometry.skinWeights = this.skinWeights.slice( 0 ); + geometry.skinIndices = this.skinIndices.slice( 0 ); + geometry.lineDistances = this.lineDistances.slice( 0 ); + + if( this.boundingBox ) geometry.boundingBox = this.boundingBox.clone(); + if( this.boundingSphere ) geometry.boundingSphere = this.boundingSphere.clone(); + + geometry.hasTangents = this.hasTangents; + + geometry.dynamic = this.dynamic; // the intermediate typed arrays will be deleted when set to false + + return geometry; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype ); + +THREE.GeometryIdCount = 0; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Geometry2 = function ( size ) { + + THREE.BufferGeometry.call( this ); + this.className = "Geometry2"; + + this.vertices = this.addAttribute( 'position', Float32Array, size, 3 ).array; + this.normals = this.addAttribute( 'normal', Float32Array, size, 3 ).array; + this.uvs = this.addAttribute( 'uv', Float32Array, size, 2 ).array; + + this.boundingBox = null; + this.boundingSphere = null; + +}; + +THREE.Geometry2.prototype = Object.create( THREE.BufferGeometry.prototype ); +/** + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author WestLangley / http://github.com/WestLangley +*/ + +THREE.Camera = function () { + + THREE.Object3D.call( this ); + + this.matrixWorldInverse = new THREE.Matrix4(); + this.projectionMatrix = new THREE.Matrix4(); + + this.normalizedViewport = { x: 0, y: 0, width: 1.0, height: 1.0 }; +}; + +THREE.Camera.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Camera.prototype.lookAt = function () { + + // This routine does not support cameras with rotated and/or translated parent(s) + + var m1 = new THREE.Matrix4(); + + return function ( vector ) { + + m1.lookAt( this.position, vector, this.up ); + + this.quaternion.setFromRotationMatrix( m1 ); + + }; + +}(); + +THREE.Camera.prototype.clone = function (camera) { + + if ( camera === undefined ) camera = new THREE.Camera(); + + THREE.Object3D.prototype.clone.call( this, camera ); + + camera.matrixWorldInverse.copy( this.matrixWorldInverse ); + camera.projectionMatrix.copy( this.projectionMatrix ); + + camera.normalizedViewport = { + x: this.normalizedViewport.x, + y: this.normalizedViewport.y, + width: this.normalizedViewport.width, + height: this.normalizedViewport.height + }; + + return camera; +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) { + + THREE.Camera.call( this ); + + this.left = left; + this.right = right; + this.top = top; + this.bottom = bottom; + + this.near = ( near !== undefined ) ? near : 0.1; + this.far = ( far !== undefined ) ? far : 2000; + + this.updateProjectionMatrix(); + +}; + +THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype ); + +THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () { + + this.projectionMatrix.makeOrthographic( this.left, this.right, this.top, this.bottom, this.near, this.far ); + + + + var viewportMatrix = new THREE.Matrix4(); + viewportMatrix.elements[0] *= this.normalizedViewport.width; + viewportMatrix.elements[1] *= this.normalizedViewport.height; + viewportMatrix.elements[12] += this.normalizedViewport.x; + viewportMatrix.elements[13] += this.normalizedViewport.y; + this.projectionMatrix = viewportMatrix.multiply( this.projectionMatrix ); +}; + +THREE.OrthographicCamera.prototype.clone = function () { + + var camera = new THREE.OrthographicCamera(); + + THREE.Camera.prototype.clone.call( this, camera ); + + camera.left = this.left; + camera.right = this.right; + camera.top = this.top; + camera.bottom = this.bottom; + + camera.near = this.near; + camera.far = this.far; + + return camera; +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author greggman / http://games.greggman.com/ + * @author zz85 / http://www.lab4games.net/zz85/blog + */ + +THREE.PerspectiveCamera = function ( fov, aspect, near, far, filmSize, filmOffset ) { + + THREE.Camera.call( this ); + + this.fov = fov !== undefined ? fov : 50; + this.aspect = aspect !== undefined ? aspect : 1; + this.near = near !== undefined ? near : 0.1; + this.far = far !== undefined ? far : 2000; + this.filmSize = filmSize !== undefined ? filmSize : new THREE.Vector2( 1, 1 ); + this.filmOffset = filmOffset !== undefined ? filmOffset : new THREE.Vector2( 0, 0 ); + + this.updateProjectionMatrix(); + +}; + +THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype ); + + +/** + * Uses Focal Length (in mm) to estimate and set FOV + * 35mm (fullframe) camera is used if frame size is not specified; + * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html + */ + +THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) { + + if ( frameHeight === undefined ) frameHeight = 24; + + this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); + this.updateProjectionMatrix(); + +} + + +/** + * Sets an offset in a larger frustum. This is useful for multi-window or + * multi-monitor/multi-machine setups. + * + * For example, if you have 3x2 monitors and each monitor is 1920x1080 and + * the monitors are in grid like this + * + * +---+---+---+ + * | A | B | C | + * +---+---+---+ + * | D | E | F | + * +---+---+---+ + * + * then for each monitor you would call it like this + * + * var w = 1920; + * var h = 1080; + * var fullWidth = w * 3; + * var fullHeight = h * 2; + * + * --A-- + * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); + * --B-- + * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); + * --C-- + * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); + * --D-- + * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); + * --E-- + * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); + * --F-- + * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); + * + * Note there is no reason monitors have to be the same size or in a grid. + */ + +THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) { + + this.fullWidth = fullWidth; + this.fullHeight = fullHeight; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + + this.updateProjectionMatrix(); + +}; + + +THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { + + if ( this.fullWidth ) { + + var aspect = this.fullWidth / this.fullHeight; + var top = Math.tan( THREE.Math.degToRad( this.fov * 0.5 ) ) * this.near; + var bottom = - top; + var left = aspect * bottom; + var right = aspect * top; + var width = Math.abs( right - left ); + var height = Math.abs( top - bottom ); + + this.projectionMatrix.makeFrustum( + left + this.x * width / this.fullWidth, + left + ( this.x + this.width ) * width / this.fullWidth, + top - ( this.y + this.height ) * height / this.fullHeight, + top - this.y * height / this.fullHeight, + this.near, + this.far, + this.filmOffset, + this.filmSize + ); + + } else { + + this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far, this.filmOffset, this.filmSize ); + + } + + var viewportMatrix = new THREE.Matrix4(); + viewportMatrix.elements[0] *= this.normalizedViewport.width; + viewportMatrix.elements[1] *= this.normalizedViewport.height; + viewportMatrix.elements[12] += this.normalizedViewport.x; + viewportMatrix.elements[13] += this.normalizedViewport.y; + this.projectionMatrix = viewportMatrix.multiply( this.projectionMatrix ); + +}; + +THREE.PerspectiveCamera.prototype.clone = function () { + + var camera = new THREE.PerspectiveCamera(); + + THREE.Camera.prototype.clone.call( this, camera ); + + camera.fov = this.fov; + camera.aspect = this.aspect; + camera.near = this.near; + camera.far = this.far; + camera.filmSize = this.filmSize; + camera.filmOffset = this.filmOffset; + + return camera; +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Light = function ( color ) { + + THREE.Object3D.call( this ); + + this.color = new THREE.Color( color ); + +}; + +THREE.Light.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Light.prototype.clone = function ( light ) { + + if ( light === undefined ) light = new THREE.Light(); + + THREE.Object3D.prototype.clone.call( this, light ); + + light.color.copy( this.color ); + + return light; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.AmbientLight = function ( color ) { + + THREE.Light.call( this, color ); + +}; + +THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype ); + +THREE.AmbientLight.prototype.clone = function () { + + var light = new THREE.AmbientLight(); + + THREE.Light.prototype.clone.call( this, light ); + + return light; + +}; + +/** + * @author bhouston / http://clara.io/ + * @author MPanknin / http://www.redplant.de/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.AreaLight = function ( color, intensity, distance, decayExponent, physicalFalloff ) { + + THREE.Light.call( this, color ); + + this.position.set( 0, 1, 0 ); + this.target = new THREE.Object3D(); + + this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.distance = ( distance !== undefined ) ? distance : 0; + this.decayExponent = ( decayExponent !== undefined ) ? decayExponent : 0; // for physically correct lights, should be 2. + this.physicalFalloff = ( physicalFalloff !== undefined ) ? physicalFalloff : false; + + this.width = 1.0; + this.height = 1.0; + + // TODO: implement shadow maps. -bhouston, Oct 15, 2014 +}; + +THREE.AreaLight.prototype = Object.create( THREE.Light.prototype ); + +THREE.AreaLight.prototype.clone = function () { + + var light = new THREE.AreaLight(); + + THREE.Light.prototype.clone.call( this, light ); + + light.target = this.target.clone(); + + light.intensity = this.intensity; + light.distance = this.distance; + light.decayExponent = this.decayExponent; + light.physicalFalloff = this.physicalFalloff; + + light.width = this.width; + light.height = this.height; + + return light; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.DirectionalLight = function ( color, intensity ) { + + THREE.Light.call( this, color ); + + this.position.set( 0, 1, 0 ); + this.target = new THREE.Object3D(); + + this.intensity = ( intensity !== undefined ) ? intensity : 1; + + this.castShadow = false; + this.onlyShadow = false; + + // + + this.shadowCameraNear = 50; + this.shadowCameraFar = 5000; + + this.shadowCameraLeft = -500; + this.shadowCameraRight = 500; + this.shadowCameraTop = 500; + this.shadowCameraBottom = -500; + + this.shadowCameraVisible = false; + + this.shadowBias = 0; + this.shadowDarkness = 0.5; + + this.shadowMapWidth = 512; + this.shadowMapHeight = 512; + + // + + this.shadowCascade = false; + + this.shadowCascadeOffset = new THREE.Vector3( 0, 0, -1000 ); + this.shadowCascadeCount = 2; + + this.shadowCascadeBias = [ 0, 0, 0 ]; + this.shadowCascadeWidth = [ 512, 512, 512 ]; + this.shadowCascadeHeight = [ 512, 512, 512 ]; + + this.shadowCascadeNearZ = [ -1.000, 0.990, 0.998 ]; + this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; + + this.shadowCascadeArray = []; + + // + + this.shadowMap = null; + this.shadowMapSize = null; + this.shadowCamera = null; + this.shadowMatrix = null; + +}; + +THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype ); + +THREE.DirectionalLight.prototype.clone = function () { + + var light = new THREE.DirectionalLight(); + + THREE.Light.prototype.clone.call( this, light ); + + light.target = this.target.clone(); + + light.intensity = this.intensity; + + light.castShadow = this.castShadow; + light.onlyShadow = this.onlyShadow; + + return light; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.HemisphereLight = function ( skyColor, groundColor, intensity ) { + + THREE.Light.call( this, skyColor ); + + this.position.set( 0, 100, 0 ); + + this.groundColor = new THREE.Color( groundColor ); + this.intensity = ( intensity !== undefined ) ? intensity : 1; + +}; + +THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype ); + +THREE.HemisphereLight.prototype.clone = function () { + + var light = new THREE.HemisphereLight(); + + THREE.Light.prototype.clone.call( this, light ); + + light.groundColor.copy( this.groundColor ); + light.intensity = this.intensity; + + return light; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.PointLight = function ( color, intensity, distance, decayExponent, physicalFalloff ) { + + THREE.Light.call( this, color ); + + this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.distance = ( distance !== undefined ) ? distance : 0; + this.decayExponent = ( decayExponent !== undefined ) ? decayExponent : 0;; // for physically correct lights, should be 2. + this.physicalFalloff = ( physicalFalloff !== undefined ) ? physicalFalloff : false; +}; + +THREE.PointLight.prototype = Object.create( THREE.Light.prototype ); + +THREE.PointLight.prototype.clone = function () { + + var light = new THREE.PointLight(); + + THREE.Light.prototype.clone.call( this, light ); + + light.intensity = this.intensity; + light.distance = this.distance; + light.decayExponent = this.decayExponent; + light.physicalFalloff = this.physicalFalloff; + + return light; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SpotLight = function ( color, intensity, distance, angle, exponent, decayExponent, physicalFalloff ) { + + THREE.Light.call( this, color ); + + this.position.set( 0, 1, 0 ); + this.target = new THREE.Object3D(); + + this.intensity = ( intensity !== undefined ) ? intensity : 1; + this.distance = ( distance !== undefined ) ? distance : 0; + this.decayExponent = ( decayExponent !== undefined ) ? decayExponent : 0;; // for physically correct lights, should be 2. + this.physicalFalloff = ( physicalFalloff !== undefined ) ? physicalFalloff : false; + + this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; + this.exponent = ( exponent !== undefined ) ? exponent : 10; + + this.castShadow = false; + this.onlyShadow = false; + + // + + this.shadowCameraNear = 50; + this.shadowCameraFar = 5000; + this.shadowCameraFov = 50; + + this.shadowCameraVisible = false; + + this.shadowBias = 0; + this.shadowDarkness = 0.5; + + this.shadowMapWidth = 512; + this.shadowMapHeight = 512; + + // + + this.shadowMap = null; + this.shadowMapSize = null; + this.shadowCamera = null; + this.shadowMatrix = null; + +}; + +THREE.SpotLight.prototype = Object.create( THREE.Light.prototype ); + +THREE.SpotLight.prototype.clone = function () { + + var light = new THREE.SpotLight(); + + THREE.Light.prototype.clone.call( this, light ); + + light.target = this.target.clone(); + + light.intensity = this.intensity; + light.distance = this.distance; + light.angle = this.angle; + light.exponent = this.exponent; + light.decayExponent = this.decayExponent; + light.physicalFalloff = this.physicalFalloff; + + light.castShadow = this.castShadow; + light.onlyShadow = this.onlyShadow; + + return light; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Loader = function ( showStatus ) { + + this.showStatus = showStatus; + this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null; + + this.onLoadStart = function () {}; + this.onLoadProgress = function () {}; + this.onLoadComplete = function () {}; + +}; + +THREE.Loader.prototype = { + + constructor: THREE.Loader, + + crossOrigin: undefined, + + addStatusElement: function () { + + var e = document.createElement( "div" ); + + e.style.position = "absolute"; + e.style.right = "0px"; + e.style.top = "0px"; + e.style.fontSize = "0.8em"; + e.style.textAlign = "left"; + e.style.background = "rgba(0,0,0,0.25)"; + e.style.color = "#fff"; + e.style.width = "120px"; + e.style.padding = "0.5em 0.5em 0.5em 0.5em"; + e.style.zIndex = 1000; + + e.innerHTML = "Loading ..."; + + return e; + + }, + + updateProgress: function ( progress ) { + + var message = "Loaded "; + + if ( progress.total ) { + + message += ( 100 * progress.loaded / progress.total ).toFixed(0) + "%"; + + + } else { + + message += ( progress.loaded / 1000 ).toFixed(2) + " KB"; + + } + + this.statusDomElement.innerHTML = message; + + }, + + extractUrlBase: function ( url ) { + + var parts = url.split( '/' ); + + if ( parts.length === 1 ) return './'; + + parts.pop(); + + return parts.join( '/' ) + '/'; + + }, + + initMaterials: function ( materials, texturePath ) { + + var array = []; + + for ( var i = 0; i < materials.length; ++ i ) { + + array[ i ] = THREE.Loader.prototype.createMaterial( materials[ i ], texturePath ); + + } + + return array; + + }, + + needsTangents: function ( materials ) { + + for( var i = 0, il = materials.length; i < il; i ++ ) { + + var m = materials[ i ]; + + if ( m instanceof THREE.ShaderMaterial ) return true; + + } + + return false; + + }, + + createMaterial: function ( m, texturePath ) { + + var _this = this; + + function is_pow2( n ) { + + var l = Math.log( n ) / Math.LN2; + return Math.floor( l ) == l; + + } + + function nearest_pow2( n ) { + + var l = Math.log( n ) / Math.LN2; + return Math.pow( 2, Math.round( l ) ); + + } + + function load_image( where, url ) { + + var image = new Image(); + + image.onload = function () { + + if ( !is_pow2( this.width ) || !is_pow2( this.height ) ) { + + var width = nearest_pow2( this.width ); + var height = nearest_pow2( this.height ); + + where.image.width = width; + where.image.height = height; + where.image.getContext( '2d' ).drawImage( this, 0, 0, width, height ); + + } else { + + where.image = this; + + } + + where.needsUpdate = true; + + }; + + if ( _this.crossOrigin !== undefined ) image.crossOrigin = _this.crossOrigin; + image.src = url; + + } + + function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) { + + var isCompressed = /\.dds$/i.test( sourceFile ); + + var fullPath = texturePath + sourceFile; + + if ( isCompressed ) { + + var texture = THREE.ImageUtils.loadCompressedTexture( fullPath ); + + where[ name ] = texture; + + } else { + + var texture = document.createElement( 'canvas' ); + + where[ name ] = new THREE.Texture( texture ); + + } + + where[ name ].sourceFile = sourceFile; + + if( repeat ) { + + where[ name ].repeat.set( repeat[ 0 ], repeat[ 1 ] ); + + if ( repeat[ 0 ] !== 1 ) where[ name ].wrapS = THREE.RepeatWrapping; + if ( repeat[ 1 ] !== 1 ) where[ name ].wrapT = THREE.RepeatWrapping; + + } + + if ( offset ) { + + where[ name ].offset.set( offset[ 0 ], offset[ 1 ] ); + + } + + if ( wrap ) { + + var wrapMap = { + "repeat": THREE.RepeatWrapping, + "mirror": THREE.MirroredRepeatWrapping + } + + if ( wrapMap[ wrap[ 0 ] ] !== undefined ) where[ name ].wrapS = wrapMap[ wrap[ 0 ] ]; + if ( wrapMap[ wrap[ 1 ] ] !== undefined ) where[ name ].wrapT = wrapMap[ wrap[ 1 ] ]; + + } + + if ( anisotropy ) { + + where[ name ].anisotropy = anisotropy; + + } + + if ( ! isCompressed ) { + + load_image( where[ name ], fullPath ); + + } + + } + + function rgb2hex( rgb ) { + + return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255; + + } + + // defaults + + var mtype = "MeshLambertMaterial"; + var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false }; + + // parameters from model file + + if ( m.shading ) { + + var shading = m.shading.toLowerCase(); + + if ( shading === "phong" ) mtype = "MeshPhongMaterial"; + else if ( shading === "basic" ) mtype = "MeshBasicMaterial"; + else if ( shading === "physical" ) mtype = "MeshPhysicalMaterial"; + + } + + if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) { + + mpars.blending = THREE[ m.blending ]; + + } + + if ( m.transparent !== undefined || m.opacity < 1.0 ) { + + mpars.transparent = m.transparent; + + } + + if ( m.depthTest !== undefined ) { + + mpars.depthTest = m.depthTest; + + } + + if ( m.depthWrite !== undefined ) { + + mpars.depthWrite = m.depthWrite; + + } + + if ( m.visible !== undefined ) { + + mpars.visible = m.visible; + + } + + if ( m.flipSided !== undefined ) { + + mpars.side = THREE.BackSide; + + } + + if ( m.doubleSided !== undefined ) { + + mpars.side = THREE.DoubleSide; + + } + + if ( m.wireframe !== undefined ) { + + mpars.wireframe = m.wireframe; + + } + + if ( m.vertexColors !== undefined ) { + + if ( m.vertexColors === "face" ) { + + mpars.vertexColors = THREE.FaceColors; + + } else if ( m.vertexColors ) { + + mpars.vertexColors = THREE.VertexColors; + + } + + } + + // colors + + if ( m.colorDiffuse ) { + + mpars.color = rgb2hex( m.colorDiffuse ); + + } else if ( m.DbgColor ) { + + mpars.color = m.DbgColor; + + } + + if ( m.colorSpecular ) { + + mpars.specular = rgb2hex( m.colorSpecular ); + + } + + if ( m.colorAmbient ) { + + mpars.ambient = rgb2hex( m.colorAmbient ); + + } + + // modifiers + + if ( m.transparency ) { + + mpars.opacity = m.transparency; + + } + + if ( m.specularCoef ) { + + mpars.shininess = m.specularCoef; + + } + + // textures + + if ( m.mapDiffuse && texturePath ) { + + create_texture( mpars, "map", m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); + + } + + if ( m.mapLight && texturePath ) { + + create_texture( mpars, "lightMap", m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); + + } + + if ( m.mapBump && texturePath ) { + + create_texture( mpars, "bumpMap", m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); + + } + + if ( m.mapNormal && texturePath ) { + + create_texture( mpars, "normalMap", m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); + + } + + if ( m.mapSpecular && texturePath ) { + + create_texture( mpars, "specularMap", m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); + + } + + // + + if ( m.mapBumpScale ) { + + mpars.bumpScale = m.mapBumpScale; + + } + + // special case for normal mapped material + + if ( m.mapNormal ) { + + var shader = THREE.ShaderLib[ "normalmap" ]; + var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); + + uniforms[ "tNormal" ].value = mpars.normalMap; + + if ( m.mapNormalFactor ) { + + uniforms[ "uNormalScale" ].value.set( m.mapNormalFactor, m.mapNormalFactor ); + + } + + if ( mpars.map ) { + + uniforms[ "tDiffuse" ].value = mpars.map; + uniforms[ "enableDiffuse" ].value = true; + + } + + if ( mpars.specularMap ) { + + uniforms[ "tSpecular" ].value = mpars.specularMap; + uniforms[ "enableSpecular" ].value = true; + + } + + if ( mpars.lightMap ) { + + uniforms[ "tAO" ].value = mpars.lightMap; + uniforms[ "enableAO" ].value = true; + + } + + // for the moment don't handle displacement texture + + uniforms[ "diffuse" ].value.setHex( mpars.color ); + uniforms[ "specular" ].value.setHex( mpars.specular ); + uniforms[ "ambient" ].value.setHex( mpars.ambient ); + + uniforms[ "shininess" ].value = mpars.shininess; + + if ( mpars.opacity !== undefined ) { + + uniforms[ "opacity" ].value = mpars.opacity; + + } + + var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; + var material = new THREE.ShaderMaterial( parameters ); + + if ( mpars.transparent ) { + + material.transparent = true; + + } + + } else { + + var material = new THREE[ mtype ]( mpars ); + + } + + if ( m.DbgName !== undefined ) material.name = m.DbgName; + + return material; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.XHRLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.XHRLoader.prototype = { + + constructor: THREE.XHRLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + var request = new XMLHttpRequest(); + + if ( onLoad !== undefined ) { + + request.addEventListener( 'load', function ( event ) { + + onLoad( event.target.responseText ); + scope.manager.itemEnd( url ); + + }, false ); + + } + + if ( onProgress !== undefined ) { + + request.addEventListener( 'progress', function ( event ) { + + onProgress( event ); + + }, false ); + + } + + if ( onError !== undefined ) { + + request.addEventListener( 'error', function ( event ) { + + onError( event ); + + }, false ); + + } + + if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin; + + request.open( 'GET', url, true ); + request.send( null ); + + scope.manager.itemStart( url ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.ImageLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.ImageLoader.prototype = { + + constructor: THREE.ImageLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + var image = document.createElement( 'img' ); + + if ( onLoad !== undefined ) { + + image.addEventListener( 'load', function ( event ) { + + scope.manager.itemEnd( url ); + onLoad( this ); + + }, false ); + + } + + if ( onProgress !== undefined ) { + + image.addEventListener( 'progress', function ( event ) { + + onProgress( event ); + + }, false ); + + } + + if ( onError !== undefined ) { + + image.addEventListener( 'error', function ( event ) { + + onError( event ); + + }, false ); + + } + + if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; + + image.src = url; + + scope.manager.itemStart( url ); + + return image; + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + } + +} + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.JSONLoader = function ( showStatus ) { + + THREE.Loader.call( this, showStatus ); + + this.withCredentials = false; + +}; + +THREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype ); + +THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) { + + var scope = this; + + // todo: unify load API to for easier SceneLoader use + + texturePath = texturePath && ( typeof texturePath === "string" ) ? texturePath : this.extractUrlBase( url ); + + this.onLoadStart(); + this.loadAjaxJSON( this, url, callback, texturePath ); + +}; + +THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) { + + var xhr = new XMLHttpRequest(); + + var length = 0; + + xhr.onreadystatechange = function () { + + if ( xhr.readyState === xhr.DONE ) { + + if ( xhr.status === 200 || xhr.status === 0 ) { + + if ( xhr.responseText ) { + + var json = JSON.parse( xhr.responseText ); + + if ( json.metadata.type === 'scene' ) { + + THREE.onerror( 'THREE.JSONLoader: "' + url + '" seems to be a Scene. Use THREE.SceneLoader instead.' ); + return; + + } + + var result = context.parse( json, texturePath ); + callback( result.geometry, result.materials ); + + } else { + + THREE.onerror( 'THREE.JSONLoader: "' + url + '" seems to be unreachable or the file is empty.' ); + + } + + // in context of more complex asset initialization + // do not block on single failed file + // maybe should go even one more level up + + context.onLoadComplete(); + + } else { + + THREE.onerror( 'THREE.JSONLoader: Couldn\'t load "' + url + '" (' + xhr.status + ')' ); + + } + + } else if ( xhr.readyState === xhr.LOADING ) { + + if ( callbackProgress ) { + + if ( length === 0 ) { + + length = xhr.getResponseHeader( 'Content-Length' ); + + } + + callbackProgress( { total: length, loaded: xhr.responseText.length } ); + + } + + } else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) { + + if ( callbackProgress !== undefined ) { + + length = xhr.getResponseHeader( "Content-Length" ); + + } + + } + + }; + + xhr.open( "GET", url, true ); + xhr.withCredentials = this.withCredentials; + xhr.send( null ); + +}; + +THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { + + var scope = this, + geometry = new THREE.Geometry(), + scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; + + parseModel( scale ); + + parseSkin(); + parseMorphing( scale ); + + geometry.computeCentroids(); + geometry.computeFaceNormals(); + geometry.computeBoundingSphere(); + + function parseModel( scale ) { + + function isBitSet( value, position ) { + + return value & ( 1 << position ); + + } + + var i, j, fi, + + offset, zLength, + + colorIndex, normalIndex, uvIndex, materialIndex, + + type, + isQuad, + hasMaterial, + hasFaceVertexUv, + hasFaceNormal, hasFaceVertexNormal, + hasFaceColor, hasFaceVertexColor, + + vertex, face, faceA, faceB, color, hex, normal, + + uvLayer, uv, u, v, + + faces = json.faces, + vertices = json.vertices, + normals = json.normals, + colors = json.colors, + + nUvLayers = 0; + + if ( json.uvs !== undefined ) { + + // disregard empty arrays + + for ( i = 0; i < json.uvs.length; i++ ) { + + if ( json.uvs[ i ].length ) nUvLayers ++; + + } + + for ( i = 0; i < nUvLayers; i++ ) { + + geometry.faceVertexUvs[ i ] = []; + + } + + } + + offset = 0; + zLength = vertices.length; + + while ( offset < zLength ) { + + vertex = new THREE.Vector3(); + + vertex.x = vertices[ offset ++ ] * scale; + vertex.y = vertices[ offset ++ ] * scale; + vertex.z = vertices[ offset ++ ] * scale; + + geometry.vertices.push( vertex ); + + } + + offset = 0; + zLength = faces.length; + + while ( offset < zLength ) { + + type = faces[ offset ++ ]; + + + isQuad = isBitSet( type, 0 ); + hasMaterial = isBitSet( type, 1 ); + hasFaceVertexUv = isBitSet( type, 3 ); + hasFaceNormal = isBitSet( type, 4 ); + hasFaceVertexNormal = isBitSet( type, 5 ); + hasFaceColor = isBitSet( type, 6 ); + hasFaceVertexColor = isBitSet( type, 7 ); + + // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); + + if ( isQuad ) { + + faceA = new THREE.Face3(); + faceA.a = faces[ offset ]; + faceA.b = faces[ offset + 1 ]; + faceA.c = faces[ offset + 3 ]; + + faceB = new THREE.Face3(); + faceB.a = faces[ offset + 1 ]; + faceB.b = faces[ offset + 2 ]; + faceB.c = faces[ offset + 3 ]; + + offset += 4; + + if ( hasMaterial ) { + + materialIndex = faces[ offset ++ ]; + faceA.materialIndex = materialIndex; + faceB.materialIndex = materialIndex; + + } + + // to get face <=> uv index correspondence + + fi = geometry.faces.length; + + if ( hasFaceVertexUv ) { + + for ( i = 0; i < nUvLayers; i++ ) { + + uvLayer = json.uvs[ i ]; + + geometry.faceVertexUvs[ i ][ fi ] = []; + geometry.faceVertexUvs[ i ][ fi + 1 ] = [] + + for ( j = 0; j < 4; j ++ ) { + + uvIndex = faces[ offset ++ ]; + + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; + + uv = new THREE.Vector2( u, v ); + + if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); + if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); + + } + + } + + } + + if ( hasFaceNormal ) { + + normalIndex = faces[ offset ++ ] * 3; + + faceA.normal.set( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); + + faceB.normal.copy( faceA.normal ); + + } + + if ( hasFaceVertexNormal ) { + + for ( i = 0; i < 4; i++ ) { + + normalIndex = faces[ offset ++ ] * 3; + + normal = new THREE.Vector3( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); + + + if ( i !== 2 ) faceA.vertexNormals.push( normal ); + if ( i !== 0 ) faceB.vertexNormals.push( normal ); + + } + + } + + + if ( hasFaceColor ) { + + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; + + faceA.color.setHex( hex ); + faceB.color.setHex( hex ); + + } + + + if ( hasFaceVertexColor ) { + + for ( i = 0; i < 4; i++ ) { + + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; + + if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) ); + if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) ); + + } + + } + + geometry.faces.push( faceA ); + geometry.faces.push( faceB ); + + } else { + + face = new THREE.Face3(); + face.a = faces[ offset ++ ]; + face.b = faces[ offset ++ ]; + face.c = faces[ offset ++ ]; + + if ( hasMaterial ) { + + materialIndex = faces[ offset ++ ]; + face.materialIndex = materialIndex; + + } + + // to get face <=> uv index correspondence + + fi = geometry.faces.length; + + if ( hasFaceVertexUv ) { + + for ( i = 0; i < nUvLayers; i++ ) { + + uvLayer = json.uvs[ i ]; + + geometry.faceVertexUvs[ i ][ fi ] = []; + + for ( j = 0; j < 3; j ++ ) { + + uvIndex = faces[ offset ++ ]; + + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; + + uv = new THREE.Vector2( u, v ); + + geometry.faceVertexUvs[ i ][ fi ].push( uv ); + + } + + } + + } + + if ( hasFaceNormal ) { + + normalIndex = faces[ offset ++ ] * 3; + + face.normal.set( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); + + } + + if ( hasFaceVertexNormal ) { + + for ( i = 0; i < 3; i++ ) { + + normalIndex = faces[ offset ++ ] * 3; + + normal = new THREE.Vector3( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); + + face.vertexNormals.push( normal ); + + } + + } + + + if ( hasFaceColor ) { + + colorIndex = faces[ offset ++ ]; + face.color.setHex( colors[ colorIndex ] ); + + } + + + if ( hasFaceVertexColor ) { + + for ( i = 0; i < 3; i++ ) { + + colorIndex = faces[ offset ++ ]; + face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) ); + + } + + } + + geometry.faces.push( face ); + + } + + } + + }; + + function parseSkin() { + + if ( json.skinWeights ) { + + for ( var i = 0, l = json.skinWeights.length; i < l; i += 2 ) { + + var x = json.skinWeights[ i ]; + var y = json.skinWeights[ i + 1 ]; + var z = 0; + var w = 0; + + geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) ); + + } + + } + + if ( json.skinIndices ) { + + for ( var i = 0, l = json.skinIndices.length; i < l; i += 2 ) { + + var a = json.skinIndices[ i ]; + var b = json.skinIndices[ i + 1 ]; + var c = 0; + var d = 0; + + geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) ); + + } + + } + + geometry.bones = json.bones; + + if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { + + THREE.onwarning( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + + geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); + + } + + + // could change this to json.animations[0] or remove completely + + geometry.animation = json.animation; + geometry.animations = json.animations; + + }; + + function parseMorphing( scale ) { + + if ( json.morphTargets !== undefined ) { + + var i, l, v, vl, dstVertices, srcVertices; + + for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) { + + geometry.morphTargets[ i ] = {}; + geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; + geometry.morphTargets[ i ].vertices = []; + + dstVertices = geometry.morphTargets[ i ].vertices; + srcVertices = json.morphTargets [ i ].vertices; + + for( v = 0, vl = srcVertices.length; v < vl; v += 3 ) { + + var vertex = new THREE.Vector3(); + vertex.x = srcVertices[ v ] * scale; + vertex.y = srcVertices[ v + 1 ] * scale; + vertex.z = srcVertices[ v + 2 ] * scale; + + dstVertices.push( vertex ); + + } + + } + + } + + if ( json.morphColors !== undefined ) { + + var i, l, c, cl, dstColors, srcColors, color; + + for ( i = 0, l = json.morphColors.length; i < l; i++ ) { + + geometry.morphColors[ i ] = {}; + geometry.morphColors[ i ].name = json.morphColors[ i ].name; + geometry.morphColors[ i ].colors = []; + + dstColors = geometry.morphColors[ i ].colors; + srcColors = json.morphColors [ i ].colors; + + for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) { + + color = new THREE.Color( 0xffaa00 ); + color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] ); + dstColors.push( color ); + + } + + } + + } + + }; + + if ( json.materials === undefined ) { + + return { geometry: geometry }; + + } else { + + var materials = this.initMaterials( json.materials, texturePath ); + + if ( this.needsTangents( materials ) ) { + + geometry.computeTangents(); + + } + + return { geometry: geometry, materials: materials }; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.LoadingManager = function ( onLoad, onProgress, onError ) { + + var scope = this; + + var loaded = 0, total = 0; + + this.onLoad = onLoad; + this.onProgress = onProgress; + this.onError = onError; + + this.itemStart = function ( url ) { + + total ++; + + }; + + this.itemEnd = function ( url ) { + + loaded ++; + + if ( scope.onProgress !== undefined ) { + + scope.onProgress( url, loaded, total ); + + } + + if ( loaded === total && scope.onLoad !== undefined ) { + + scope.onLoad(); + + } + + }; + +}; + +THREE.DefaultLoadingManager = new THREE.LoadingManager(); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.BufferGeometryLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.BufferGeometryLoader.prototype = { + + constructor: THREE.BufferGeometryLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new THREE.XHRLoader(); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { + + onLoad( scope.parse( JSON.parse( text ) ) ); + + } ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + parse: function ( json ) { + + var geometry = new THREE.BufferGeometry(); + + var attributes = json.attributes; + var offsets = json.offsets; + var boundingSphere = json.boundingSphere; + + for ( var key in attributes ) { + + var attribute = attributes[ key ]; + + geometry.attributes[ key ] = { + itemSize: attribute.itemSize, + array: new self[ attribute.type ]( attribute.array ) + } + + } + + if ( offsets !== undefined ) { + + geometry.offsets = JSON.parse( JSON.stringify( offsets ) ); + + } + + if ( boundingSphere !== undefined ) { + + geometry.boundingSphere = new THREE.Sphere( + new THREE.Vector3().fromArray( boundingSphere.center !== undefined ? boundingSphere.center : [ 0, 0, 0 ] ), + boundingSphere.radius + ); + + } + + return geometry; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Geometry2Loader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.Geometry2Loader.prototype = { + + constructor: THREE.Geometry2Loader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new THREE.XHRLoader(); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { + + onLoad( scope.parse( JSON.parse( text ) ) ); + + } ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + parse: function ( json ) { + + var geometry = new THREE.Geometry2( json.vertices.length / 3 ); + + var attributes = [ 'vertices', 'normals', 'uvs' ]; + var boundingSphere = json.boundingSphere; + + for ( var key in attributes ) { + + var attribute = attributes[ key ]; + geometry[ attribute ].set( json[ attribute ] ); + + } + + if ( boundingSphere !== undefined ) { + + geometry.boundingSphere = new THREE.Sphere( + new THREE.Vector3().fromArray( boundingSphere.center !== undefined ? boundingSphere.center : [ 0, 0, 0 ] ), + boundingSphere.radius + ); + + } + + return geometry; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.MaterialLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.MaterialLoader.prototype = { + + constructor: THREE.MaterialLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new THREE.XHRLoader(); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { + + onLoad( scope.parse( JSON.parse( text ) ) ); + + } ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + parse: function ( json ) { + + var material = new THREE[ json.type ]; + + if ( json.color !== undefined ) material.color.setHex( json.color ); + if ( json.ambient !== undefined ) material.ambient.setHex( json.ambient ); + if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); + if ( json.specular !== undefined ) material.specular.setHex( json.specular ); + if ( json.falloff !== undefined ) material.falloff = json.falloff; + if ( json.falloffColor !== undefined ) material.falloffColor.setHex( json.falloffColor ); + if ( json.roughness !== undefined ) material.roughness = json.roughness; + if ( json.metallic !== undefined ) material.metallic = json.metallic; + if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat; + if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness; + if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy; + if ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation; + if ( json.translucency !== undefined ) material.translucency.setHex( json.translucency ); + if ( json.translucencyNormalAlpha !== undefined ) material.translucencyNormalAlpha = json.translucencyNormalAlpha; + if ( json.translucencyNormalPower !== undefined ) material.translucencyNormalPower = json.translucencyNormalPower; + if ( json.translucencyViewAlpha !== undefined ) material.translucencyViewAlpha = json.translucencyViewAlpha; + if ( json.translucencyViewPower !== undefined ) material.translucencyViewPower = json.translucencyViewPower; + if ( json.shininess !== undefined ) material.shininess = json.shininess; + if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; + if ( json.blending !== undefined ) material.blending = json.blending; + if ( json.side !== undefined ) material.side = json.side; + if ( json.opacity !== undefined ) material.opacity = json.opacity; + if ( json.transparent !== undefined ) material.transparent = json.transparent; + if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; + + if ( json.materials !== undefined ) { + + for ( var i = 0, l = json.materials.length; i < l; i ++ ) { + + material.materials.push( this.parse( json.materials[ i ] ) ); + + } + + } + + return material; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.ObjectLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.ObjectLoader.prototype = { + + constructor: THREE.ObjectLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new THREE.XHRLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { + + onLoad( scope.parse( JSON.parse( text ) ) ); + + } ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + parse: function ( json ) { + + var geometries = this.parseGeometries( json.geometries ); + var materials = this.parseMaterials( json.materials ); + var object = this.parseObject( json.object, geometries, materials ); + + return object; + + }, + + parseGeometries: function ( json ) { + + var geometries = {}; + + if ( json !== undefined ) { + + var geometryLoader = new THREE.JSONLoader(); + var geometry2Loader = new THREE.Geometry2Loader(); + var bufferGeometryLoader = new THREE.BufferGeometryLoader(); + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var geometry; + var data = json[ i ]; + + switch ( data.type ) { + + case 'PlaneGeometry': + + geometry = new THREE.PlaneGeometry( + data.width, + data.height, + data.widthSegments, + data.heightSegments + ); + + break; + + case 'BoxGeometry': + case 'CubeGeometry': // DEPRECATED + + geometry = new THREE.BoxGeometry( + data.width, + data.height, + data.depth, + data.widthSegments, + data.heightSegments, + data.depthSegments + ); + + break; + + case 'CircleGeometry': + + geometry = new THREE.CircleGeometry( + data.radius, + data.segments + ); + + break; + + case 'CylinderGeometry': + + geometry = new THREE.CylinderGeometry( + data.radiusTop, + data.radiusBottom, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded + ); + + break; + + case 'SphereGeometry': + + geometry = new THREE.SphereGeometry( + data.radius, + data.widthSegments, + data.heightSegments, + data.phiStart, + data.phiLength, + data.thetaStart, + data.thetaLength + ); + + break; + + case 'IcosahedronGeometry': + + geometry = new THREE.IcosahedronGeometry( + data.radius, + data.detail + ); + + break; + + case 'TorusGeometry': + + geometry = new THREE.TorusGeometry( + data.radius, + data.tube, + data.radialSegments, + data.tubularSegments, + data.arc + ); + + break; + + case 'TorusKnotGeometry': + + geometry = new THREE.TorusKnotGeometry( + data.radius, + data.tube, + data.radialSegments, + data.tubularSegments, + data.p, + data.q, + data.heightScale + ); + + break; + + case 'BufferGeometry': + + geometry = bufferGeometryLoader.parse( data.data ); + + break; + + case 'Geometry2': + + geometry = geometry2Loader.parse( data.data ); + + break; + + case 'Geometry': + + geometry = geometryLoader.parse( data.data ).geometry; + + break; + + } + + geometry.uuid = data.uuid; + + if ( data.name !== undefined ) geometry.name = data.name; + + geometries[ data.uuid ] = geometry; + + } + + } + + return geometries; + + }, + + parseMaterials: function ( json ) { + + var materials = {}; + + if ( json !== undefined ) { + + var loader = new THREE.MaterialLoader(); + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var data = json[ i ]; + var material = loader.parse( data ); + + material.uuid = data.uuid; + + if ( data.name !== undefined ) material.name = data.name; + + materials[ data.uuid ] = material; + + } + + } + + return materials; + + }, + + parseObject: function () { + + var matrix = new THREE.Matrix4(); + + return function ( data, geometries, materials ) { + + var object; + + switch ( data.type ) { + + case 'Scene': + + object = new THREE.Scene(); + + break; + + case 'PerspectiveCamera': + + object = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); + + break; + + case 'OrthographicCamera': + + object = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); + + break; + + case 'AmbientLight': + + object = new THREE.AmbientLight( data.color ); + + break; + + case 'DirectionalLight': + + object = new THREE.DirectionalLight( data.color, data.intensity ); + + break; + + case 'PointLight': + + object = new THREE.PointLight( data.color, data.intensity, data.distance, data.decay, data.physicalFalloff ); + + break; + + case 'SpotLight': + + object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent, data.decay, data.physicalFalloff ); + + break; + + case 'HemisphereLight': + + object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity ); + + break; + + case 'AreaLight': + + object = new THREE.AreaLight( data.color, data.intensity, data.distance, data.decayExponent, data.decay, data.physicalFalloff ); + object.width = data.width || 1; + object.height = data.height || 1; + + break; + + case 'Mesh': + + var geometry = geometries[ data.geometry ]; + var material = materials[ data.material ]; + + if ( geometry === undefined ) { + + THREE.onerror( 'THREE.ObjectLoader: Undefined geometry ' + data.geometry ); + + } + + if ( material === undefined ) { + + THREE.onerror( 'THREE.ObjectLoader: Undefined material ' + data.material ); + + } + + object = new THREE.Mesh( geometry, material ); + + break; + + case 'Sprite': + + var material = materials[ data.material ]; + + if ( material === undefined ) { + + THREE.onerror( 'THREE.ObjectLoader: Undefined material ' + data.material ); + + } + + object = new THREE.Sprite( material ); + + break; + + default: + + object = new THREE.Object3D(); + + } + + object.uuid = data.uuid; + + if ( data.name !== undefined ) object.name = data.name; + if ( data.matrix !== undefined ) { + + matrix.fromArray( data.matrix ); + matrix.decompose( object.position, object.quaternion, object.scale ); + + } else { + + if ( data.position !== undefined ) object.position.fromArray( data.position ); + if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); + if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); + + } + + if ( data.visible !== undefined ) object.visible = data.visible; + if ( data.userData !== undefined ) object.userData = data.userData; + + if ( data.children !== undefined ) { + + for ( var child in data.children ) { + + object.add( this.parseObject( data.children[ child ], geometries, materials ) ); + + } + + } + + return object; + + } + + }() + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SceneLoader = function () { + + this.onLoadStart = function () {}; + this.onLoadProgress = function() {}; + this.onLoadComplete = function () {}; + + this.callbackSync = function () {}; + this.callbackProgress = function () {}; + + this.geometryHandlers = {}; + this.hierarchyHandlers = {}; + + this.addGeometryHandler( "ascii", THREE.JSONLoader ); + +}; + +THREE.SceneLoader.prototype = { + + constructor: THREE.SceneLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new THREE.XHRLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( text ) { + + scope.parse( JSON.parse( text ), onLoad, url ); + + } ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + }, + + addGeometryHandler: function ( typeID, loaderClass ) { + + this.geometryHandlers[ typeID ] = { "loaderClass": loaderClass }; + + }, + + addHierarchyHandler: function ( typeID, loaderClass ) { + + this.hierarchyHandlers[ typeID ] = { "loaderClass": loaderClass }; + + }, + + parse: function ( json, callbackFinished, url ) { + + var scope = this; + + var urlBase = THREE.Loader.prototype.extractUrlBase( url ); + + var geometry, material, camera, fog, + texture, images, color, + light, hex, intensity, + counter_models, counter_textures, + total_models, total_textures, + result; + + var target_array = []; + + var data = json; + + // async geometry loaders + + for ( var typeID in this.geometryHandlers ) { + + var loaderClass = this.geometryHandlers[ typeID ][ "loaderClass" ]; + this.geometryHandlers[ typeID ][ "loaderObject" ] = new loaderClass(); + + } + + // async hierachy loaders + + for ( var typeID in this.hierarchyHandlers ) { + + var loaderClass = this.hierarchyHandlers[ typeID ][ "loaderClass" ]; + this.hierarchyHandlers[ typeID ][ "loaderObject" ] = new loaderClass(); + + } + + counter_models = 0; + counter_textures = 0; + + result = { + + scene: new THREE.Scene(), + geometries: {}, + face_materials: {}, + materials: {}, + textures: {}, + objects: {}, + cameras: {}, + lights: {}, + fogs: {}, + empties: {}, + groups: {} + + }; + + if ( data.transform ) { + + var position = data.transform.position, + rotation = data.transform.rotation, + scale = data.transform.scale; + + if ( position ) { + + result.scene.position.fromArray( position ); + + } + + if ( rotation ) { + + result.scene.rotation.fromArray( rotation ); + + } + + if ( scale ) { + + result.scene.scale.fromArray( scale ); + + } + + if ( position || rotation || scale ) { + + result.scene.updateMatrix(); + result.scene.updateMatrixWorld(); + + } + + } + + function get_url( source_url, url_type ) { + + if ( url_type == "relativeToHTML" ) { + + return source_url; + + } else { + + return urlBase + source_url; + + } + + }; + + // toplevel loader function, delegates to handle_children + + function handle_objects() { + + handle_children( result.scene, data.objects ); + + } + + // handle all the children from the loaded json and attach them to given parent + + function handle_children( parent, children ) { + + var mat, dst, pos, rot, scl, quat; + + for ( var objID in children ) { + + // check by id if child has already been handled, + // if not, create new object + + var object = result.objects[ objID ]; + var objJSON = children[ objID ]; + + if ( object === undefined ) { + + // meshes + + if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) { + + if ( objJSON.loading === undefined ) { + + var reservedTypes = { + "type": 1, "url": 1, "material": 1, + "position": 1, "rotation": 1, "scale" : 1, + "visible": 1, "children": 1, "userData": 1, + "skin": 1, "morph": 1, "mirroredLoop": 1, "duration": 1 + }; + + var loaderParameters = {}; + + for ( var parType in objJSON ) { + + if ( ! ( parType in reservedTypes ) ) { + + loaderParameters[ parType ] = objJSON[ parType ]; + + } + + } + + material = result.materials[ objJSON.material ]; + + objJSON.loading = true; + + var loader = scope.hierarchyHandlers[ objJSON.type ][ "loaderObject" ]; + + // ColladaLoader + + if ( loader.options ) { + + loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ) ); + + // UTF8Loader + // OBJLoader + + } else { + + loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ), loaderParameters ); + + } + + } + + } else if ( objJSON.geometry !== undefined ) { + + geometry = result.geometries[ objJSON.geometry ]; + + // geometry already loaded + + if ( geometry ) { + + var needsTangents = false; + + material = result.materials[ objJSON.material ]; + needsTangents = material instanceof THREE.ShaderMaterial; + + pos = objJSON.position; + rot = objJSON.rotation; + scl = objJSON.scale; + mat = objJSON.matrix; + quat = objJSON.quaternion; + + // use materials from the model file + // if there is no material specified in the object + + if ( ! objJSON.material ) { + + material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); + + } + + // use materials from the model file + // if there is just empty face material + // (must create new material as each model has its own face material) + + if ( ( material instanceof THREE.MeshFaceMaterial ) && material.materials.length === 0 ) { + + material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); + + } + + if ( material instanceof THREE.MeshFaceMaterial ) { + + for ( var i = 0; i < material.materials.length; i ++ ) { + + needsTangents = needsTangents || ( material.materials[ i ] instanceof THREE.ShaderMaterial ); + + } + + } + + if ( needsTangents ) { + + geometry.computeTangents(); + + } + + if ( objJSON.skin ) { + + object = new THREE.SkinnedMesh( geometry, material ); + + } else if ( objJSON.morph ) { + + object = new THREE.MorphAnimMesh( geometry, material ); + + if ( objJSON.duration !== undefined ) { + + object.duration = objJSON.duration; + + } + + if ( objJSON.time !== undefined ) { + + object.time = objJSON.time; + + } + + if ( objJSON.mirroredLoop !== undefined ) { + + object.mirroredLoop = objJSON.mirroredLoop; + + } + + if ( material.morphNormals ) { + + geometry.computeMorphNormals(); + + } + + } else { + + object = new THREE.Mesh( geometry, material ); + + } + + object.name = objID; + + if ( mat ) { + + object.matrixAutoUpdate = false; + object.matrix.set( + mat[0], mat[1], mat[2], mat[3], + mat[4], mat[5], mat[6], mat[7], + mat[8], mat[9], mat[10], mat[11], + mat[12], mat[13], mat[14], mat[15] + ); + + } else { + + object.position.fromArray( pos ); + + if ( quat ) { + + object.quaternion.fromArray( quat ); + + } else { + + object.rotation.fromArray( rot ); + + } + + object.scale.fromArray( scl ); + + } + + object.visible = objJSON.visible; + object.castShadow = objJSON.castShadow; + object.receiveShadow = objJSON.receiveShadow; + + parent.add( object ); + + result.objects[ objID ] = object; + + } + + // lights + + } else if ( objJSON.type === "AmbientLight" || objJSON.type === "PointLight" || + objJSON.type === "DirectionalLight" || objJSON.type === "SpotLight" || + objJSON.type === "HemisphereLight" || objJSON.type === "AreaLight" ) { + + var color = objJSON.color; + var intensity = objJSON.intensity; + var distance = objJSON.distance; + var position = objJSON.position; + var rotation = objJSON.rotation; + + switch ( objJSON.type ) { + + case 'AmbientLight': + light = new THREE.AmbientLight( color ); + break; + + case 'PointLight': + light = new THREE.PointLight( color, intensity, distance ); + light.position.fromArray( position ); + break; + + case 'DirectionalLight': + light = new THREE.DirectionalLight( color, intensity ); + light.position.fromArray( objJSON.direction ); + break; + + case 'SpotLight': + light = new THREE.SpotLight( color, intensity, distance, 1 ); + light.angle = objJSON.angle; + light.position.fromArray( position ); + light.target.set( position[ 0 ], position[ 1 ] - distance, position[ 2 ] ); + light.target.applyEuler( new THREE.Euler( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ], 'XYZ' ) ); + break; + + case 'HemisphereLight': + light = new THREE.DirectionalLight( color, intensity, distance ); + light.target.set( position[ 0 ], position[ 1 ] - distance, position[ 2 ] ); + light.target.applyEuler( new THREE.Euler( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ], 'XYZ' ) ); + break; + + case 'AreaLight': + light = new THREE.AreaLight(color, intensity); + light.position.fromArray( position ); + light.width = objJSON.size; + light.height = objJSON.size_y; + break; + + } + + parent.add( light ); + + light.name = objID; + result.lights[ objID ] = light; + result.objects[ objID ] = light; + + // cameras + + } else if ( objJSON.type === "PerspectiveCamera" || objJSON.type === "OrthographicCamera" ) { + + pos = objJSON.position; + rot = objJSON.rotation; + quat = objJSON.quaternion; + + if ( objJSON.type === "PerspectiveCamera" ) { + + camera = new THREE.PerspectiveCamera( objJSON.fov, objJSON.aspect, objJSON.near, objJSON.far ); + + } else if ( objJSON.type === "OrthographicCamera" ) { + + camera = new THREE.OrthographicCamera( objJSON.left, objJSON.right, objJSON.top, objJSON.bottom, objJSON.near, objJSON.far ); + + } + + camera.name = objID; + camera.position.fromArray( pos ); + + if ( quat !== undefined ) { + + camera.quaternion.fromArray( quat ); + + } else if ( rot !== undefined ) { + + camera.rotation.fromArray( rot ); + + } + + parent.add( camera ); + + result.cameras[ objID ] = camera; + result.objects[ objID ] = camera; + + // pure Object3D + + } else { + + pos = objJSON.position; + rot = objJSON.rotation; + scl = objJSON.scale; + quat = objJSON.quaternion; + + object = new THREE.Object3D(); + object.name = objID; + object.position.fromArray( pos ); + + if ( quat ) { + + object.quaternion.fromArray( quat ); + + } else { + + object.rotation.fromArray( rot ); + + } + + object.scale.fromArray( scl ); + object.visible = ( objJSON.visible !== undefined ) ? objJSON.visible : false; + + parent.add( object ); + + result.objects[ objID ] = object; + result.empties[ objID ] = object; + + } + + if ( object ) { + + if ( objJSON.userData !== undefined ) { + + for ( var key in objJSON.userData ) { + + var value = objJSON.userData[ key ]; + object.userData[ key ] = value; + + } + + } + + if ( objJSON.groups !== undefined ) { + + for ( var i = 0; i < objJSON.groups.length; i ++ ) { + + var groupID = objJSON.groups[ i ]; + + if ( result.groups[ groupID ] === undefined ) { + + result.groups[ groupID ] = []; + + } + + result.groups[ groupID ].push( objID ); + + } + + } + + } + + } + + if ( object !== undefined && objJSON.children !== undefined ) { + + handle_children( object, objJSON.children ); + + } + + } + + }; + + function handle_mesh( geo, mat, id ) { + + result.geometries[ id ] = geo; + result.face_materials[ id ] = mat; + handle_objects(); + + }; + + function handle_hierarchy( node, id, parent, material, obj ) { + + var p = obj.position; + var r = obj.rotation; + var q = obj.quaternion; + var s = obj.scale; + + node.position.fromArray( p ); + + if ( q ) { + + node.quaternion.fromArray( q ); + + } else { + + node.rotation.fromArray( r ); + + } + + node.scale.fromArray( s ); + + // override children materials + // if object material was specified in JSON explicitly + + if ( material ) { + + node.traverse( function ( child ) { + + child.material = material; + + } ); + + } + + // override children visibility + // with root node visibility as specified in JSON + + var visible = ( obj.visible !== undefined ) ? obj.visible : true; + + node.traverse( function ( child ) { + + child.visible = visible; + + } ); + + parent.add( node ); + + node.name = id; + + result.objects[ id ] = node; + handle_objects(); + + }; + + function create_callback_geometry( id ) { + + return function ( geo, mat ) { + + geo.name = id; + + handle_mesh( geo, mat, id ); + + counter_models -= 1; + + scope.onLoadComplete(); + + async_callback_gate(); + + } + + }; + + function create_callback_hierachy( id, parent, material, obj ) { + + return function ( event ) { + + var result; + + // loaders which use EventDispatcher + + if ( event.content ) { + + result = event.content; + + // ColladaLoader + + } else if ( event.dae ) { + + result = event.scene; + + + // UTF8Loader + + } else { + + result = event; + + } + + handle_hierarchy( result, id, parent, material, obj ); + + counter_models -= 1; + + scope.onLoadComplete(); + + async_callback_gate(); + + } + + }; + + function create_callback_embed( id ) { + + return function ( geo, mat ) { + + geo.name = id; + + result.geometries[ id ] = geo; + result.face_materials[ id ] = mat; + + } + + }; + + function async_callback_gate() { + + var progress = { + + totalModels : total_models, + totalTextures : total_textures, + loadedModels : total_models - counter_models, + loadedTextures : total_textures - counter_textures + + }; + + scope.callbackProgress( progress, result ); + + scope.onLoadProgress(); + + if ( counter_models === 0 && counter_textures === 0 ) { + + finalize(); + callbackFinished( result ); + + } + + }; + + function finalize() { + + // take care of targets which could be asynchronously loaded objects + + for ( var i = 0; i < target_array.length; i ++ ) { + + var ta = target_array[ i ]; + + var target = result.objects[ ta.targetName ]; + + if ( target ) { + + ta.object.target = target; + + } else { + + // if there was error and target of specified name doesn't exist in the scene file + // create instead dummy target + // (target must be added to scene explicitly as parent is already added) + + ta.object.target = new THREE.Object3D(); + result.scene.add( ta.object.target ); + + } + + ta.object.target.userData.targetInverse = ta.object; + + } + + }; + + var callbackTexture = function ( count ) { + + counter_textures -= count; + async_callback_gate(); + + scope.onLoadComplete(); + + }; + + // must use this instead of just directly calling callbackTexture + // because of closure in the calling context loop + + var generateTextureCallback = function ( count ) { + + return function () { + + callbackTexture( count ); + + }; + + }; + + function traverse_json_hierarchy( objJSON, callback ) { + + callback( objJSON ); + + if ( objJSON.children !== undefined ) { + + for ( var objChildID in objJSON.children ) { + + traverse_json_hierarchy( objJSON.children[ objChildID ], callback ); + + } + + } + + }; + + // first go synchronous elements + + // fogs + + var fogID, fogJSON; + + for ( fogID in data.fogs ) { + + fogJSON = data.fogs[ fogID ]; + + if ( fogJSON.type === "linear" ) { + + fog = new THREE.Fog( 0x000000, fogJSON.near, fogJSON.far ); + + } else if ( fogJSON.type === "exp2" ) { + + fog = new THREE.FogExp2( 0x000000, fogJSON.density ); + + } + + color = fogJSON.color; + fog.color.setRGB( color[0], color[1], color[2] ); + + result.fogs[ fogID ] = fog; + + } + + // now come potentially asynchronous elements + + // geometries + + // count how many geometries will be loaded asynchronously + + var geoID, geoJSON; + + for ( geoID in data.geometries ) { + + geoJSON = data.geometries[ geoID ]; + + if ( geoJSON.type in this.geometryHandlers ) { + + counter_models += 1; + + scope.onLoadStart(); + + } + + } + + // count how many hierarchies will be loaded asynchronously + + for ( var objID in data.objects ) { + + traverse_json_hierarchy( data.objects[ objID ], function ( objJSON ) { + + if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) { + + counter_models += 1; + + scope.onLoadStart(); + + } + + }); + + } + + total_models = counter_models; + + for ( geoID in data.geometries ) { + + geoJSON = data.geometries[ geoID ]; + + if ( geoJSON.type === "cube" ) { + + geometry = new THREE.BoxGeometry( geoJSON.width, geoJSON.height, geoJSON.depth, geoJSON.widthSegments, geoJSON.heightSegments, geoJSON.depthSegments ); + geometry.name = geoID; + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "plane" ) { + + geometry = new THREE.PlaneGeometry( geoJSON.width, geoJSON.height, geoJSON.widthSegments, geoJSON.heightSegments ); + geometry.name = geoID; + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "sphere" ) { + + geometry = new THREE.SphereGeometry( geoJSON.radius, geoJSON.widthSegments, geoJSON.heightSegments ); + geometry.name = geoID; + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "cylinder" ) { + + geometry = new THREE.CylinderGeometry( geoJSON.topRad, geoJSON.botRad, geoJSON.height, geoJSON.radSegs, geoJSON.heightSegs ); + geometry.name = geoID; + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "torus" ) { + + geometry = new THREE.TorusGeometry( geoJSON.radius, geoJSON.tube, geoJSON.segmentsR, geoJSON.segmentsT ); + geometry.name = geoID; + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type === "icosahedron" ) { + + geometry = new THREE.IcosahedronGeometry( geoJSON.radius, geoJSON.subdivisions ); + geometry.name = geoID; + result.geometries[ geoID ] = geometry; + + } else if ( geoJSON.type in this.geometryHandlers ) { + + var loaderParameters = {}; + + for ( var parType in geoJSON ) { + + if ( parType !== "type" && parType !== "url" ) { + + loaderParameters[ parType ] = geoJSON[ parType ]; + + } + + } + + var loader = this.geometryHandlers[ geoJSON.type ][ "loaderObject" ]; + loader.load( get_url( geoJSON.url, data.urlBaseType ), create_callback_geometry( geoID ), loaderParameters ); + + } else if ( geoJSON.type === "embedded" ) { + + var modelJson = data.embeds[ geoJSON.id ], + texture_path = ""; + + // pass metadata along to jsonLoader so it knows the format version + + modelJson.metadata = data.metadata; + + if ( modelJson ) { + + var jsonLoader = this.geometryHandlers[ "ascii" ][ "loaderObject" ]; + var model = jsonLoader.parse( modelJson, texture_path ); + create_callback_embed( geoID )( model.geometry, model.materials ); + + } + + } + + } + + // textures + + // count how many textures will be loaded asynchronously + + var textureID, textureJSON; + + for ( textureID in data.textures ) { + + textureJSON = data.textures[ textureID ]; + + if ( textureJSON.url instanceof Array ) { + + counter_textures += textureJSON.url.length; + + for( var n = 0; n < textureJSON.url.length; n ++ ) { + + scope.onLoadStart(); + + } + + } else { + + counter_textures += 1; + + scope.onLoadStart(); + + } + + } + + total_textures = counter_textures; + + for ( textureID in data.textures ) { + + textureJSON = data.textures[ textureID ]; + + if ( textureJSON.mapping !== undefined && THREE[ textureJSON.mapping ] !== undefined ) { + + textureJSON.mapping = new THREE[ textureJSON.mapping ](); + + } + + if ( textureJSON.url instanceof Array ) { + + var count = textureJSON.url.length; + var url_array = []; + + for( var i = 0; i < count; i ++ ) { + + url_array[ i ] = get_url( textureJSON.url[ i ], data.urlBaseType ); + + } + + var isCompressed = /\.dds$/i.test( url_array[ 0 ] ); + + if ( isCompressed ) { + + texture = THREE.ImageUtils.loadCompressedTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); + + } else { + + texture = THREE.ImageUtils.loadTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); + + } + + } else { + + var isCompressed = /\.dds$/i.test( textureJSON.url ); + var fullUrl = get_url( textureJSON.url, data.urlBaseType ); + var textureCallback = generateTextureCallback( 1 ); + + if ( isCompressed ) { + + texture = THREE.ImageUtils.loadCompressedTexture( fullUrl, textureJSON.mapping, textureCallback ); + + } else { + + texture = THREE.ImageUtils.loadTexture( fullUrl, textureJSON.mapping, textureCallback ); + + } + + if ( THREE[ textureJSON.minFilter ] !== undefined ) + texture.minFilter = THREE[ textureJSON.minFilter ]; + + if ( THREE[ textureJSON.magFilter ] !== undefined ) + texture.magFilter = THREE[ textureJSON.magFilter ]; + + if ( textureJSON.anisotropy ) texture.anisotropy = textureJSON.anisotropy; + + if ( textureJSON.repeat ) { + + texture.repeat.set( textureJSON.repeat[ 0 ], textureJSON.repeat[ 1 ] ); + + if ( textureJSON.repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping; + if ( textureJSON.repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping; + + } + + if ( textureJSON.offset ) { + + texture.offset.set( textureJSON.offset[ 0 ], textureJSON.offset[ 1 ] ); + + } + + // handle wrap after repeat so that default repeat can be overriden + + if ( textureJSON.wrap ) { + + var wrapMap = { + "repeat": THREE.RepeatWrapping, + "mirror": THREE.MirroredRepeatWrapping + } + + if ( wrapMap[ textureJSON.wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ textureJSON.wrap[ 0 ] ]; + if ( wrapMap[ textureJSON.wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ textureJSON.wrap[ 1 ] ]; + + } + + } + + result.textures[ textureID ] = texture; + + } + + // materials + + var matID, matJSON; + var parID; + + for ( matID in data.materials ) { + + matJSON = data.materials[ matID ]; + + for ( parID in matJSON.parameters ) { + + if ( parID === "envMap" || parID === "map" || parID === "lightMap" || parID === "bumpMap" ) { + + matJSON.parameters[ parID ] = result.textures[ matJSON.parameters[ parID ] ]; + + } else if ( parID === "shading" ) { + + matJSON.parameters[ parID ] = ( matJSON.parameters[ parID ] === "flat" ) ? THREE.FlatShading : THREE.SmoothShading; + + } else if ( parID === "side" ) { + + if ( matJSON.parameters[ parID ] == "double" ) { + + matJSON.parameters[ parID ] = THREE.DoubleSide; + + } else if ( matJSON.parameters[ parID ] == "back" ) { + + matJSON.parameters[ parID ] = THREE.BackSide; + + } else { + + matJSON.parameters[ parID ] = THREE.FrontSide; + + } + + } else if ( parID === "blending" ) { + + matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.NormalBlending; + + } else if ( parID === "combine" ) { + + matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.MultiplyOperation; + + } else if ( parID === "vertexColors" ) { + + if ( matJSON.parameters[ parID ] == "face" ) { + + matJSON.parameters[ parID ] = THREE.FaceColors; + + // default to vertex colors if "vertexColors" is anything else face colors or 0 / null / false + + } else if ( matJSON.parameters[ parID ] ) { + + matJSON.parameters[ parID ] = THREE.VertexColors; + + } + + } else if ( parID === "wrapRGB" ) { + + var v3 = matJSON.parameters[ parID ]; + matJSON.parameters[ parID ] = new THREE.Vector3( v3[ 0 ], v3[ 1 ], v3[ 2 ] ); + + } + + } + + if ( matJSON.parameters.opacity !== undefined && matJSON.parameters.opacity < 1.0 ) { + + matJSON.parameters.transparent = true; + + } + + if ( matJSON.parameters.normalMap ) { + + var shader = THREE.ShaderLib[ "normalmap" ]; + var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); + + var diffuse = matJSON.parameters.color; + var specular = matJSON.parameters.specular; + var ambient = matJSON.parameters.ambient; + var shininess = matJSON.parameters.shininess; + + uniforms[ "tNormal" ].value = result.textures[ matJSON.parameters.normalMap ]; + + if ( matJSON.parameters.normalScale ) { + + uniforms[ "uNormalScale" ].value.set( matJSON.parameters.normalScale[ 0 ], matJSON.parameters.normalScale[ 1 ] ); + + } + + if ( matJSON.parameters.map ) { + + uniforms[ "tDiffuse" ].value = matJSON.parameters.map; + uniforms[ "enableDiffuse" ].value = true; + + } + + if ( matJSON.parameters.envMap ) { + + uniforms[ "tCube" ].value = matJSON.parameters.envMap; + uniforms[ "enableReflection" ].value = true; + uniforms[ "reflectivity" ].value = matJSON.parameters.reflectivity; + + } + + if ( matJSON.parameters.lightMap ) { + + uniforms[ "tAO" ].value = matJSON.parameters.lightMap; + uniforms[ "enableAO" ].value = true; + + } + + if ( matJSON.parameters.specularMap ) { + + uniforms[ "tSpecular" ].value = result.textures[ matJSON.parameters.specularMap ]; + uniforms[ "enableSpecular" ].value = true; + + } + + if ( matJSON.parameters.displacementMap ) { + + uniforms[ "tDisplacement" ].value = result.textures[ matJSON.parameters.displacementMap ]; + uniforms[ "enableDisplacement" ].value = true; + + uniforms[ "uDisplacementBias" ].value = matJSON.parameters.displacementBias; + uniforms[ "uDisplacementScale" ].value = matJSON.parameters.displacementScale; + + } + + uniforms[ "diffuse" ].value.setHex( diffuse ); + uniforms[ "specular" ].value.setHex( specular ); + uniforms[ "ambient" ].value.setHex( ambient ); + + uniforms[ "shininess" ].value = shininess; + + if ( matJSON.parameters.opacity ) { + + uniforms[ "opacity" ].value = matJSON.parameters.opacity; + + } + + var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; + + material = new THREE.ShaderMaterial( parameters ); + + } else { + + material = new THREE[ matJSON.type ]( matJSON.parameters ); + + } + + material.name = matID; + + result.materials[ matID ] = material; + + } + + // second pass through all materials to initialize MeshFaceMaterials + // that could be referring to other materials out of order + + for ( matID in data.materials ) { + + matJSON = data.materials[ matID ]; + + if ( matJSON.parameters.materials ) { + + var materialArray = []; + + for ( var i = 0; i < matJSON.parameters.materials.length; i ++ ) { + + var label = matJSON.parameters.materials[ i ]; + materialArray.push( result.materials[ label ] ); + + } + + result.materials[ matID ].materials = materialArray; + + } + + } + + // objects ( synchronous init of procedural primitives ) + + handle_objects(); + + // defaults + + if ( result.cameras && data.defaults.camera ) { + + result.currentCamera = result.cameras[ data.defaults.camera ]; + + } + + if ( result.fogs && data.defaults.fog ) { + + result.scene.fog = result.fogs[ data.defaults.fog ]; + + } + + // synchronous callback + + scope.callbackSync( result ); + + // just in case there are no async elements + + async_callback_gate(); + + } + +} + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.TextureLoader = function ( manager ) { + + this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + +}; + +THREE.TextureLoader.prototype = { + + constructor: THREE.TextureLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new THREE.ImageLoader( scope.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.load( url, function ( image ) { + + var texture = new THREE.Texture( image ); + texture.needsUpdate = true; + + if ( onLoad !== undefined ) { + + onLoad( texture ); + + } + + } ); + + }, + + setCrossOrigin: function ( value ) { + + this.crossOrigin = value; + + } + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Material = function () { + + this.id = THREE.MaterialIdCount ++; + this.uuid = THREE.Math.generateUUID(); + + this.name = ''; + + this.side = THREE.FrontSide; + + this.opacity = 1; + this.transparent = false; + + this.blending = THREE.NormalBlending; + + this.blendSrc = THREE.SrcAlphaFactor; + this.blendDst = THREE.OneMinusSrcAlphaFactor; + this.blendEquation = THREE.AddEquation; + + this.depthTest = true; + this.depthWrite = true; + + this.polygonOffset = false; + this.polygonOffsetFactor = 0; + this.polygonOffsetUnits = 0; + + this.alphaTest = 0; + + this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer + + this.visible = true; + + this.needsUpdate = true; + +}; + +THREE.Material.prototype = { + + constructor: THREE.Material, + + setValues: function ( values ) { + + if ( values === undefined ) return; + + for ( var key in values ) { + + var newValue = values[ key ]; + + if ( newValue === undefined ) { + + THREE.onwarning( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); + continue; + + } + + if ( key in this ) { + + var currentValue = this[ key ]; + + if ( currentValue instanceof THREE.Color ) { + + currentValue.set( newValue ); + + } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) { + + currentValue.copy( newValue ); + + } else if ( key == 'overdraw') { + + // ensure overdraw is backwards-compatable with legacy boolean type + this[ key ] = Number(newValue); + + } else { + + this[ key ] = newValue; + + } + + } + + } + + }, + + clone: function ( material ) { + + if ( material === undefined ) material = new THREE.Material(); + + material.name = this.name; + + material.side = this.side; + + material.opacity = this.opacity; + material.transparent = this.transparent; + + material.blending = this.blending; + + material.blendSrc = this.blendSrc; + material.blendDst = this.blendDst; + material.blendEquation = this.blendEquation; + + material.depthTest = this.depthTest; + material.depthWrite = this.depthWrite; + + material.polygonOffset = this.polygonOffset; + material.polygonOffsetFactor = this.polygonOffsetFactor; + material.polygonOffsetUnits = this.polygonOffsetUnits; + + material.alphaTest = this.alphaTest; + + material.overdraw = this.overdraw; + + material.visible = this.visible; + + return material; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +THREE.EventDispatcher.prototype.apply( THREE.Material.prototype ); + +THREE.MaterialIdCount = 0; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * linewidth: , + * linecap: "round", + * linejoin: "round", + * + * vertexColors: + * + * fog: + * } + */ + +THREE.LineBasicMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); + + this.linewidth = 1; + this.linecap = 'round'; + this.linejoin = 'round'; + + this.vertexColors = false; + + this.fog = true; + + this.setValues( parameters ); + +}; + +THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.LineBasicMaterial.prototype.clone = function () { + + var material = new THREE.LineBasicMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + + material.linewidth = this.linewidth; + material.linecap = this.linecap; + material.linejoin = this.linejoin; + + material.vertexColors = this.vertexColors; + + material.fog = this.fog; + + return material; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * linewidth: , + * + * scale: , + * dashSize: , + * gapSize: , + * + * vertexColors: + * + * fog: + * } + */ + +THREE.LineDashedMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); + + this.linewidth = 1; + + this.scale = 1; + this.dashSize = 3; + this.gapSize = 1; + + this.vertexColors = false; + + this.fog = true; + + this.setValues( parameters ); + +}; + +THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.LineDashedMaterial.prototype.clone = function () { + + var material = new THREE.LineDashedMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + + material.linewidth = this.linewidth; + + material.scale = this.scale; + material.dashSize = this.dashSize; + material.gapSize = this.gapSize; + + material.vertexColors = this.vertexColors; + + material.fog = this.fog; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * lightMap: new THREE.Texture( ), + * + * specularMap: new THREE.Texture( ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: , + * refractionRatio: , + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: , + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: , + * morphTargets: , + * + * fog: + * } + */ + +THREE.MeshBasicMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); // emissive + + this.map = null; + + this.lightMap = null; + + this.specularMap = null; + + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.fog = true; + + this.shading = THREE.SmoothShading; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.vertexColors = THREE.NoColors; + + this.skinning = false; + this.morphTargets = false; + + this.setValues( parameters ); + +}; + +THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshBasicMaterial.prototype.clone = function () { + + var material = new THREE.MeshBasicMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + + material.map = this.map; + + material.lightMap = this.lightMap; + + material.specularMap = this.specularMap; + + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; + + material.fog = this.fog; + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * ambient: , + * emissive: , + * opacity: , + * + * map: new THREE.Texture( ), + * + * lightMap: new THREE.Texture( ), + * + * specularMap: new THREE.Texture( ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: , + * refractionRatio: , + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: , + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: , + * morphTargets: , + * morphNormals: , + * + * fog: + * } + */ + +THREE.MeshLambertMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); // diffuse + this.ambient = new THREE.Color( 0xffffff ); + this.emissive = new THREE.Color( 0x000000 ); + + this.wrapAround = false; + this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); + + this.map = null; + + this.lightMap = null; + + this.specularMap = null; + + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.fog = true; + + this.shading = THREE.SmoothShading; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.vertexColors = THREE.NoColors; + + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; + + this.setValues( parameters ); + +}; + +THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshLambertMaterial.prototype.clone = function () { + + var material = new THREE.MeshLambertMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.ambient.copy( this.ambient ); + material.emissive.copy( this.emissive ); + + material.wrapAround = this.wrapAround; + material.wrapRGB.copy( this.wrapRGB ); + + material.map = this.map; + + material.lightMap = this.lightMap; + + material.specularMap = this.specularMap; + + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; + + material.fog = this.fog; + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * ambient: , + * emissive: , + * specular: , + * shininess: , + * opacity: , + * + * map: new THREE.Texture( ), + * + * lightMap: new THREE.Texture( ), + * + * bumpMap: new THREE.Texture( ), + * bumpScale: , + * + * normalMap: new THREE.Texture( ), + * normalScale: , + * + * specularMap: new THREE.Texture( ), + * + * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), + * combine: THREE.Multiply, + * reflectivity: , + * refractionRatio: , + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: , + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: , + * morphTargets: , + * morphNormals: , + * + * fog: + * } + */ + +THREE.MeshPhongMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); // diffuse + this.ambient = new THREE.Color( 0x000000 ); + this.emissive = new THREE.Color( 0x000000 ); + this.specular = new THREE.Color( 0xffffff ); + this.shininess = 30; + + this.wrapAround = false; + this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); + + this.map = null; + this.opacityMap = null; + + this.lightMap = null; + this.emissiveMap = null; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalScale = new THREE.Vector2( 1, 1 ); + + this.specularMap = null; + + this.envMap = null; + this.combine = THREE.MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; + + this.fog = true; + + this.shading = THREE.SmoothShading; + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.vertexColors = THREE.NoColors; + + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; + + this.setValues( parameters ); + +}; + +THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshPhongMaterial.prototype.clone = function () { + + var material = new THREE.MeshPhongMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.ambient.copy( this.ambient ); + material.emissive.copy( this.emissive ); + material.specular.copy( this.specular ); + material.shininess = this.shininess; + + material.wrapAround = this.wrapAround; + material.wrapRGB.copy( this.wrapRGB ); + + material.map = this.map; + material.opacityMap = this.opacityMap; + + material.lightMap = this.lightMap; + material.emissiveMap = this.emissiveMap; + + material.bumpMap = this.bumpMap; + material.bumpScale = this.bumpScale; + + material.normalMap = this.normalMap; + material.normalScale.copy( this.normalScale ); + + material.specularMap = this.specularMap; + + material.envMap = this.envMap; + material.combine = this.combine; + material.reflectivity = this.reflectivity; + material.refractionRatio = this.refractionRatio; + + material.fog = this.fog; + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; + + return material; + +}; + +/** + * + * @author bhouston / http://clara.io/ + * + */ + +THREE.MeshPhysicalMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); // diffuse + this.map = null; + this.opacityMap = null; + this.fog = true; + + this.falloff = false; + this.falloffColor = new THREE.Color( 0xffffff ); + this.falloffMap = null; + this.falloffBlendParams = new THREE.Vector4( 1.0, 0.0, 0.0, 1.0 ); + + this.specular = new THREE.Color( 0xffffff ); + this.specularMap = null; + + this.roughness = 0.5; + this.roughnessMap = null; + + this.metallic = 0.0; + this.metallicMap = null; + + this.clearCoat = 0.0; // 0 means no clear coat, 1 means complete clear coat. + this.clearCoatRoughness = 0.2; + + this.anisotropy = 0.0; // valid range is [-1,1].-1 is max vertical elongation, 0 is normal, +1 is max horizontal elongation + this.anisotropyMap = null; // only R is read and considered to be anisotropy. To get negative values, use texture brightness, gain + this.anisotropyRotation = 0.0; // converted to radias via multiplication by 2*PI. Thus the range [ 0 - 1 ] maps to radian [0, PI]. + this.anisotropyRotationMap = null; // only R is read and considered to be anisotropyRotation. + + this.translucency = new THREE.Color( 0x000000 ); + this.translucencyMap = null; + this.translucencyNormalAlpha = 0.75; + this.translucencyNormalPower = 1.0; + this.translucencyViewPower = 2.0; + this.translucencyViewAlpha = 0.75; + + this.bumpMap = null; + this.bumpScale = 1; + + this.normalMap = null; + this.normalScale = new THREE.Vector2( 1, 1 ); + + this.emissive = new THREE.Color( 0x000000 ); + this.emissiveMap = null; // given off arbitrarily by the object in all directions. Basically GI. + + this.ambient = new THREE.Color( 0x000000 ); + this.lightMap = null; // incoming light + + this.envMap = null; // Incoming environmental light. + this.diffuseEnvMap = null; // irradiance light. + + this.combine = THREE.AddOperation; + + this.shading = THREE.SmoothShading + + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; + + this.blending = THREE.CustomBlending; + this.blendSrc = THREE.OneFactor; // output of shader must be premultiplied + this.blendDst = THREE.OneMinusSrcAlphaFactor; + this.blendEquation = THREE.AddEquation; + + this.vertexColors = THREE.NoColors; + + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; + + this.setValues( parameters ); +}; + +THREE.MeshPhysicalMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshPhysicalMaterial.prototype.clone = function () { + + var material = new THREE.MeshPhysicalMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.map = this.map; + material.opacityMap = this.opacityMap; + material.fog = this.fog; + + material.falloff = this.falloff; + material.falloffColor.copy( this.falloffColor ); + material.falloffMap = this.falloffMap; + material.falloffBlendParams.copy( this.falloffBlendParams ); + + material.specular.copy( this.specular ); + material.specularMap = this.specularMap; + + material.roughness = this.roughness; + material.roughnessMap = this.roughnessMap; + material.metallic = this.metallic; + material.metallicMap = this.metallicMap; + + material.shading = this.shading; + + material.translucency.copy( this.translucency ); + material.translucencyMap = this.translucencyMap; + material.translucencyNormalAlpha = this.translucencyNormalAlpha; + material.translucencyNormalPower = this.translucencyNormalPower; + material.translucencyViewPower = this.translucencyViewPower; + material.translucencyViewAlpha = this.translucencyViewAlpha; + + material.bumpMap = this.bumpMap; + material.bumpScale = this.bumpScale; + + material.normalMap = this.normalMap; + material.normalScale.copy( this.normalScale ); + + material.emissive.copy( this.emissive ); + material.emissiveMap = this.emissiveMap; + + material.ambient.copy( this.ambient ); + material.lightMap = this.lightMap; + + material.envMap = this.envMap; + material.diffuseEnvMap = this.diffuseEnvMap; + + material.combine = this.combine; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + material.wireframeLinecap = this.wireframeLinecap; + material.wireframeLinejoin = this.wireframeLinejoin; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * opacity: , + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: + * } + */ + +THREE.MeshDepthMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.setValues( parameters ); + +}; + +THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshDepthMaterial.prototype.clone = function () { + + var material = new THREE.MeshDepthMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * + * parameters = { + * opacity: , + * + * shading: THREE.FlatShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: + * } + */ + +THREE.MeshNormalMaterial = function ( parameters ) { + + THREE.Material.call( this, parameters ); + + this.shading = THREE.FlatShading; + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.morphTargets = false; + + this.setValues( parameters ); + +}; + +THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.MeshNormalMaterial.prototype.clone = function () { + + var material = new THREE.MeshNormalMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.MeshFaceMaterial = function ( materials ) { + + this.materials = materials instanceof Array ? materials : []; + +}; + +THREE.MeshFaceMaterial.prototype.clone = function () { + + var material = new THREE.MeshFaceMaterial(); + + for ( var i = 0; i < this.materials.length; i ++ ) { + + material.materials.push( this.materials[ i ].clone() ); + + } + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * size: , + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * vertexColors: , + * + * fog: + * } + */ + +THREE.ParticleSystemMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); + + this.map = null; + + this.size = 1; + this.sizeAttenuation = true; + + this.vertexColors = false; + + this.fog = true; + + this.setValues( parameters ); + +}; + +THREE.ParticleSystemMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.ParticleSystemMaterial.prototype.clone = function () { + + var material = new THREE.ParticleSystemMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + + material.map = this.map; + + material.size = this.size; + material.sizeAttenuation = this.sizeAttenuation; + + material.vertexColors = this.vertexColors; + + material.fog = this.fog; + + return material; + +}; + +// backwards compatibility + +THREE.ParticleBasicMaterial = THREE.ParticleSystemMaterial; + +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * fragmentShader: , + * vertexShader: , + * + * uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } }, + * + * defines: { "label" : "value" }, + * + * shading: THREE.SmoothShading, + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * wireframe: , + * wireframeLinewidth: , + * + * lights: , + * + * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, + * + * skinning: , + * morphTargets: , + * morphNormals: , + * + * fog: + * } + */ + +THREE.ShaderMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.shaderID = null; + this.fragmentShader = "void main() {}"; + this.vertexShader = "void main() {}"; + this.uniforms = {}; + this.defines = {}; + this.attributes = null; + + this.shading = THREE.SmoothShading; + + this.linewidth = 1; + + this.wireframe = false; + this.wireframeLinewidth = 1; + + this.fog = false; // set to use scene fog + + this.lights = false; // set to use scene lights + + this.vertexColors = THREE.NoColors; // set to use "color" attribute stream + + this.skinning = false; // set to use skinning attribute streams + + this.morphTargets = false; // set to use morph targets + this.morphNormals = false; // set to use morph normals + + // When rendered geometry doesn't include these attributes but the material does, + // use these default values in WebGL. This avoids errors when buffer data is missing. + this.defaultAttributeValues = { + "color" : [ 1, 1, 1], + "uv" : [ 0, 0 ], + "uv2" : [ 0, 0 ] + }; + + // By default, bind position to attribute index 0. In WebGL, attribute 0 + // should always be used to avoid potentially expensive emulation. + this.index0AttributeName = "position"; + + this.setValues( parameters ); + +}; + +THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.ShaderMaterial.prototype.clone = function () { + + var material = new THREE.ShaderMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.fragmentShader = this.fragmentShader; + material.vertexShader = this.vertexShader; + + material.uniforms = THREE.UniformsUtils.clone( this.uniforms ); + + material.attributes = this.attributes; + material.defines = this.defines; + + material.shading = this.shading; + + material.wireframe = this.wireframe; + material.wireframeLinewidth = this.wireframeLinewidth; + + material.fog = this.fog; + + material.lights = this.lights; + + material.vertexColors = this.vertexColors; + + material.skinning = this.skinning; + + material.morphTargets = this.morphTargets; + material.morphNormals = this.morphNormals; + + return material; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * + * blending: THREE.NormalBlending, + * depthTest: , + * depthWrite: , + * + * uvOffset: new THREE.Vector2(), + * uvScale: new THREE.Vector2(), + * + * fog: + * } + */ + +THREE.SpriteMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + // defaults + + this.color = new THREE.Color( 0xffffff ); + this.map = null; + + this.rotation = 0; + + this.fog = false; + + // set parameters + + this.setValues( parameters ); + +}; + +THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.SpriteMaterial.prototype.clone = function () { + + var material = new THREE.SpriteMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.map = this.map; + + material.rotation = this.rotation; + + material.fog = this.fog; + + return material; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * + * parameters = { + * color: , + * program: , + * opacity: , + * blending: THREE.NormalBlending + * } + */ + +THREE.SpriteCanvasMaterial = function ( parameters ) { + + THREE.Material.call( this ); + + this.color = new THREE.Color( 0xffffff ); + this.program = function ( context, color ) {}; + + this.setValues( parameters ); + +}; + +THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype ); + +THREE.SpriteCanvasMaterial.prototype.clone = function () { + + var material = new THREE.SpriteCanvasMaterial(); + + THREE.Material.prototype.clone.call( this, material ); + + material.color.copy( this.color ); + material.program = this.program; + + return material; + +}; + +// backwards compatibility + +THREE.ParticleCanvasMaterial = THREE.SpriteCanvasMaterial; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author szimek / https://github.com/szimek/ + * @author bhouston / https://clara.io/ + */ + +THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + + this.id = THREE.TextureIdCount ++; + this.uuid = THREE.Math.generateUUID(); + + this.name = ''; + + this.image = image; + this.mipmaps = []; + + this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping(); + + this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; + this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; + + this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; + this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; + + this.anisotropy = anisotropy !== undefined ? anisotropy : 1; + + this.format = format !== undefined ? format : THREE.RGBAFormat; + this.type = type !== undefined ? type : THREE.UnsignedByteType; + + this.offset = new THREE.Vector2( 0, 0 ); + this.repeat = new THREE.Vector2( 1, 1 ); + + // formula used + // x' = ( x - gainPivot ) * gain + brightness + gainPivot + // for standard contrast adjust, set gain to contrast, and gainPivot to 0.5 + this.invert = false; + this.gainPivot = 0.0; + this.gain = 1.0; + this.brightness = 0.0; + this.encoding = THREE.sRGB; + + this.generateMipmaps = true; + this.premultiplyAlpha = false; + this.flipY = true; + this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) + + this._needsUpdate = false; + this.onUpdate = null; + +}; + +THREE.Texture.prototype = { + + constructor: THREE.Texture, + + get needsUpdate () { + + return this._needsUpdate; + + }, + + set needsUpdate ( value ) { + + if ( value === true ) this.update(); + + this._needsUpdate = value; + + }, + + clone: function ( texture ) { + + if ( texture === undefined ) texture = new THREE.Texture(); + + texture.image = this.image; + texture.mipmaps = this.mipmaps.slice(0); + + texture.mapping = this.mapping; + + texture.wrapS = this.wrapS; + texture.wrapT = this.wrapT; + + texture.magFilter = this.magFilter; + texture.minFilter = this.minFilter; + + texture.anisotropy = this.anisotropy; + + texture.format = this.format; + texture.type = this.type; + + texture.offset.copy( this.offset ); + texture.repeat.copy( this.repeat ); + + texture.invert = this.invert; + texture.gainPivot = this.gainPivot; + texture.gain = this.gain; + texture.brightness = this.brightness; + texture.encoding = this.encoding; + + texture.generateMipmaps = this.generateMipmaps; + texture.premultiplyAlpha = this.premultiplyAlpha; + texture.flipY = this.flipY; + texture.unpackAlignment = this.unpackAlignment; + + return texture; + + }, + + update: function () { + + this.dispatchEvent( { type: 'update' } ); + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype ); + +THREE.TextureIdCount = 0; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { + + THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.image = { width: width, height: height }; + this.mipmaps = mipmaps; + + this.generateMipmaps = false; // WebGL currently can't generate mipmaps for compressed textures, they must be embedded in DDS file + +}; + +THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype ); + +THREE.CompressedTexture.prototype.clone = function () { + + var texture = new THREE.CompressedTexture(); + + THREE.Texture.prototype.clone.call( this, texture ); + + return texture; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { + + THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.image = { data: data, width: width, height: height }; + +}; + +THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype ); + +THREE.DataTexture.prototype.clone = function () { + + var texture = new THREE.DataTexture(); + + THREE.Texture.prototype.clone.call( this, texture ); + + return texture; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.ParticleSystem = function ( geometry, material ) { + + THREE.Object3D.call( this ); + + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.ParticleSystemMaterial( { color: Math.random() * 0xffffff } ); + + this.sortParticles = false; + this.frustumCulled = false; + +}; + +THREE.ParticleSystem.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.ParticleSystem.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.ParticleSystem( this.geometry, this.material ); + + object.sortParticles = this.sortParticles; + + THREE.Object3D.prototype.clone.call( this, object ); + + return object; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Line = function ( geometry, material, type ) { + + THREE.Object3D.call( this ); + + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); + + this.type = ( type !== undefined ) ? type : THREE.LineStrip; + +}; + +THREE.LineStrip = 0; +THREE.LinePieces = 1; + +THREE.Line.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Line.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.type ); + + THREE.Object3D.prototype.clone.call( this, object ); + + return object; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author mikael emtinger / http://gomo.se/ + * @author jonobr1 / http://jonobr1.com/ + */ + +THREE.Mesh = function ( geometry, material ) { + + THREE.Object3D.call( this ); + + this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); + this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ); + + this.updateMorphTargets(); + +}; + +THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Mesh.prototype.updateMorphTargets = function () { + + if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) { + + this.morphTargetBase = -1; + this.morphTargetForcedOrder = []; + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; + + for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) { + + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; + + } + + } + +}; + +THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { + + if ( this.morphTargetDictionary[ name ] !== undefined ) { + + return this.morphTargetDictionary[ name ]; + + } + + THREE.onwarning( "THREE.Mesh.getMorphTargetIndexByName: morph target " + name + " does not exist. Returning 0." ); + + return 0; + +}; + +THREE.Mesh.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material ); + + THREE.Object3D.prototype.clone.call( this, object ); + + return object; + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Bone = function( belongsToSkin ) { + + THREE.Object3D.call( this ); + + this.skin = belongsToSkin; + this.skinMatrix = new THREE.Matrix4(); + +}; + +THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Bone.prototype.update = function ( parentSkinMatrix, forceUpdate ) { + + // update local + + if ( this.matrixAutoUpdate ) { + + forceUpdate |= this.updateMatrix(); + + } + + // update skin matrix + + if ( forceUpdate || this.matrixWorldNeedsUpdate ) { + + if( parentSkinMatrix ) { + + this.skinMatrix.multiplyMatrices( parentSkinMatrix, this.matrix ); + + } else { + + this.skinMatrix.copy( this.matrix ); + + } + + this.matrixWorldNeedsUpdate = false; + forceUpdate = true; + + } + + // update children + + var child, i, l = this.children.length; + + for ( i = 0; i < l; i ++ ) { + + this.children[ i ].update( this.skinMatrix, forceUpdate ); + + } + +}; + + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { + + THREE.Mesh.call( this, geometry, material ); + + // + + this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; + + // init bones + + this.identityMatrix = new THREE.Matrix4(); + + this.bones = []; + this.boneMatrices = []; + + var b, bone, gbone, p, q, s; + + if ( this.geometry && this.geometry.bones !== undefined ) { + + for ( b = 0; b < this.geometry.bones.length; b ++ ) { + + gbone = this.geometry.bones[ b ]; + + p = gbone.pos; + q = gbone.rotq; + s = gbone.scl; + + bone = this.addBone(); + + bone.name = gbone.name; + bone.position.set( p[0], p[1], p[2] ); + bone.quaternion.set( q[0], q[1], q[2], q[3] ); + + if ( s !== undefined ) { + + bone.scale.set( s[0], s[1], s[2] ); + + } else { + + bone.scale.set( 1, 1, 1 ); + + } + + } + + for ( b = 0; b < this.bones.length; b ++ ) { + + gbone = this.geometry.bones[ b ]; + bone = this.bones[ b ]; + + if ( gbone.parent === -1 ) { + + this.add( bone ); + + } else { + + this.bones[ gbone.parent ].add( bone ); + + } + + } + + // + + var nBones = this.bones.length; + + if ( this.useVertexTexture ) { + + // layout (1 matrix = 4 pixels) + // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) + // with 8x8 pixel texture max 16 bones (8 * 8 / 4) + // 16x16 pixel texture max 64 bones (16 * 16 / 4) + // 32x32 pixel texture max 256 bones (32 * 32 / 4) + // 64x64 pixel texture max 1024 bones (64 * 64 / 4) + + var size; + + if ( nBones > 256 ) + size = 64; + else if ( nBones > 64 ) + size = 32; + else if ( nBones > 16 ) + size = 16; + else + size = 8; + + this.boneTextureWidth = size; + this.boneTextureHeight = size; + + this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel + this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType ); + this.boneTexture.minFilter = THREE.NearestFilter; + this.boneTexture.magFilter = THREE.NearestFilter; + this.boneTexture.generateMipmaps = false; + this.boneTexture.flipY = false; + + } else { + + this.boneMatrices = new Float32Array( 16 * nBones ); + + } + + this.pose(); + + } + +}; + +THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype ); + +THREE.SkinnedMesh.prototype.addBone = function( bone ) { + + if ( bone === undefined ) { + + bone = new THREE.Bone( this ); + + } + + this.bones.push( bone ); + + return bone; + +}; + +THREE.SkinnedMesh.prototype.updateMatrixWorld = function () { + + var offsetMatrix = new THREE.Matrix4(); + + return function ( force ) { + + this.matrixAutoUpdate && this.updateMatrix(); + + // update matrixWorld + + if ( this.matrixWorldNeedsUpdate || force ) { + + if ( this.parent ) { + + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + + } else { + + this.matrixWorld.copy( this.matrix ); + + } + + this.matrixWorldNeedsUpdate = false; + + force = true; + + } + + // update children + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + var child = this.children[ i ]; + + if ( child instanceof THREE.Bone ) { + + child.update( this.identityMatrix, false ); + + } else { + + child.updateMatrixWorld( true ); + + } + + } + + // make a snapshot of the bones' rest position + + if ( this.boneInverses == undefined ) { + + this.boneInverses = []; + + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + + var inverse = new THREE.Matrix4(); + + inverse.getInverse( this.bones[ b ].skinMatrix ); + + this.boneInverses.push( inverse ); + + } + + } + + // flatten bone matrices to array + + for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { + + // compute the offset between the current and the original transform; + + // TODO: we could get rid of this multiplication step if the skinMatrix + // was already representing the offset; however, this requires some + // major changes to the animation system + + offsetMatrix.multiplyMatrices( this.bones[ b ].skinMatrix, this.boneInverses[ b ] ); + offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 ); + + } + + if ( this.useVertexTexture ) { + + this.boneTexture.needsUpdate = true; + + } + + }; + +}(); + +THREE.SkinnedMesh.prototype.pose = function () { + + this.updateMatrixWorld( true ); + + this.normalizeSkinWeights(); + +}; + +THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () { + + if ( this.geometry instanceof THREE.Geometry ) { + + for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) { + + var sw = this.geometry.skinWeights[ i ]; + + var scale = 1.0 / sw.lengthManhattan(); + + if ( scale !== Infinity ) { + + sw.multiplyScalar( scale ); + + } else { + + sw.set( 1 ); // this will be normalized by the shader anyway + + } + + } + + } else { + + // skinning weights assumed to be normalized for THREE.BufferGeometry + + } + +}; + +THREE.SkinnedMesh.prototype.clone = function ( object ) { + + if ( object === undefined ) { + + object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture ); + + } + + THREE.Mesh.prototype.clone.call( this, object ); + + return object; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.MorphAnimMesh = function ( geometry, material ) { + + THREE.Mesh.call( this, geometry, material ); + + // API + + this.duration = 1000; // milliseconds + this.mirroredLoop = false; + this.time = 0; + + // internals + + this.lastKeyframe = 0; + this.currentKeyframe = 0; + + this.direction = 1; + this.directionBackwards = false; + + this.setFrameRange( 0, this.geometry.morphTargets.length - 1 ); + +}; + +THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype ); + +THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) { + + this.startKeyframe = start; + this.endKeyframe = end; + + this.length = this.endKeyframe - this.startKeyframe + 1; + +}; + +THREE.MorphAnimMesh.prototype.setDirectionForward = function () { + + this.direction = 1; + this.directionBackwards = false; + +}; + +THREE.MorphAnimMesh.prototype.setDirectionBackward = function () { + + this.direction = -1; + this.directionBackwards = true; + +}; + +THREE.MorphAnimMesh.prototype.parseAnimations = function () { + + var geometry = this.geometry; + + if ( ! geometry.animations ) geometry.animations = {}; + + var firstAnimation, animations = geometry.animations; + + var pattern = /([a-z]+)(\d+)/; + + for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { + + var morph = geometry.morphTargets[ i ]; + var parts = morph.name.match( pattern ); + + if ( parts && parts.length > 1 ) { + + var label = parts[ 1 ]; + var num = parts[ 2 ]; + + if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: -Infinity }; + + var animation = animations[ label ]; + + if ( i < animation.start ) animation.start = i; + if ( i > animation.end ) animation.end = i; + + if ( ! firstAnimation ) firstAnimation = label; + + } + + } + + geometry.firstAnimation = firstAnimation; + +}; + +THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) { + + if ( ! this.geometry.animations ) this.geometry.animations = {}; + + this.geometry.animations[ label ] = { start: start, end: end }; + +}; + +THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) { + + var animation = this.geometry.animations[ label ]; + + if ( animation ) { + + this.setFrameRange( animation.start, animation.end ); + this.duration = 1000 * ( ( animation.end - animation.start ) / fps ); + this.time = 0; + + } else { + + THREE.onwarning( "animation[" + label + "] undefined" ); + + } + +}; + +THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) { + + var frameTime = this.duration / this.length; + + this.time += this.direction * delta; + + if ( this.mirroredLoop ) { + + if ( this.time > this.duration || this.time < 0 ) { + + this.direction *= -1; + + if ( this.time > this.duration ) { + + this.time = this.duration; + this.directionBackwards = true; + + } + + if ( this.time < 0 ) { + + this.time = 0; + this.directionBackwards = false; + + } + + } + + } else { + + this.time = this.time % this.duration; + + if ( this.time < 0 ) this.time += this.duration; + + } + + var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 ); + + if ( keyframe !== this.currentKeyframe ) { + + this.morphTargetInfluences[ this.lastKeyframe ] = 0; + this.morphTargetInfluences[ this.currentKeyframe ] = 1; + + this.morphTargetInfluences[ keyframe ] = 0; + + this.lastKeyframe = this.currentKeyframe; + this.currentKeyframe = keyframe; + + } + + var mix = ( this.time % frameTime ) / frameTime; + + if ( this.directionBackwards ) { + + mix = 1 - mix; + + } + + this.morphTargetInfluences[ this.currentKeyframe ] = mix; + this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix; + +}; + +THREE.MorphAnimMesh.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material ); + + object.duration = this.duration; + object.mirroredLoop = this.mirroredLoop; + object.time = this.time; + + object.lastKeyframe = this.lastKeyframe; + object.currentKeyframe = this.currentKeyframe; + + object.direction = this.direction; + object.directionBackwards = this.directionBackwards; + + THREE.Mesh.prototype.clone.call( this, object ); + + return object; + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.LOD = function () { + + THREE.Object3D.call( this ); + + this.objects = []; + +}; + + +THREE.LOD.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.LOD.prototype.addLevel = function ( object, distance ) { + + if ( distance === undefined ) distance = 0; + + distance = Math.abs( distance ); + + for ( var l = 0; l < this.objects.length; l ++ ) { + + if ( distance < this.objects[ l ].distance ) { + + break; + + } + + } + + this.objects.splice( l, 0, { distance: distance, object: object } ); + this.add( object ); + +}; + +THREE.LOD.prototype.getObjectForDistance = function ( distance ) { + + for ( var i = 1, l = this.objects.length; i < l; i ++ ) { + + if ( distance < this.objects[ i ].distance ) { + + break; + + } + + } + + return this.objects[ i - 1 ].object; + +}; + +THREE.LOD.prototype.update = function () { + + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + + return function ( camera ) { + + if ( this.objects.length > 1 ) { + + v1.setFromMatrixPosition( camera.matrixWorld ); + v2.setFromMatrixPosition( this.matrixWorld ); + + var distance = v1.distanceTo( v2 ); + + this.objects[ 0 ].object.visible = true; + + for ( var i = 1, l = this.objects.length; i < l; i ++ ) { + + if ( distance >= this.objects[ i ].distance ) { + + this.objects[ i - 1 ].object.visible = false; + this.objects[ i ].object.visible = true; + + } else { + + break; + + } + + } + + for( ; i < l; i ++ ) { + + this.objects[ i ].object.visible = false; + + } + + } + + }; + +}(); + +THREE.LOD.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.LOD(); + + THREE.Object3D.prototype.clone.call( this, object ); + + for ( var i = 0, l = this.objects.length; i < l; i ++ ) { + var x = this.objects[i].object.clone(); + x.visible = i === 0; + object.addLevel( x, this.objects[i].distance ); + } + + return object; + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Sprite = ( function () { + + var geometry = new THREE.Geometry2( 3 ); + geometry.vertices.set( [ - 0.5, - 0.5, 0, 0.5, - 0.5, 0, 0.5, 0.5, 0 ] ); + + return function ( material ) { + + THREE.Object3D.call( this ); + + this.geometry = geometry; + this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial(); + + }; + +} )(); + +THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype ); + +/* + * Custom update matrix + */ + +THREE.Sprite.prototype.updateMatrix = function () { + + this.matrix.compose( this.position, this.quaternion, this.scale ); + + this.matrixWorldNeedsUpdate = true; + +}; + +THREE.Sprite.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.Sprite( this.material ); + + THREE.Object3D.prototype.clone.call( this, object ); + + return object; + +}; + +// Backwards compatibility + +THREE.Particle = THREE.Sprite; +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.Scene = function () { + + THREE.Object3D.call( this ); + + this.fog = null; + this.overrideMaterial = null; + + this.autoUpdate = true; // checked by the renderer + this.matrixAutoUpdate = false; + + this.__lights = []; + + this.__objectsAdded = []; + this.__objectsRemoved = []; + +}; + +THREE.Scene.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Scene.prototype.__addObject = function ( object ) { + + if ( object instanceof THREE.Light ) { + + if ( this.__lights.indexOf( object ) === - 1 ) { + + this.__lights.push( object ); + + } + + if ( object.target && object.target.parent === undefined ) { + + this.add( object.target ); + + } + + } else if ( !( object instanceof THREE.Camera || object instanceof THREE.Bone ) ) { + + this.__objectsAdded.push( object ); + + // check if previously removed + + var i = this.__objectsRemoved.indexOf( object ); + + if ( i !== -1 ) { + + this.__objectsRemoved.splice( i, 1 ); + + } + + } + + this.dispatchEvent( { type: 'objectAdded', object: object } ); + object.dispatchEvent( { type: 'addedToScene', scene: this } ); + + for ( var c = 0; c < object.children.length; c ++ ) { + + this.__addObject( object.children[ c ] ); + + } + +}; + +THREE.Scene.prototype.__removeObject = function ( object ) { + + if ( object instanceof THREE.Light ) { + + var i = this.__lights.indexOf( object ); + + if ( i !== -1 ) { + + this.__lights.splice( i, 1 ); + + } + + if ( object.shadowCascadeArray ) { + + for ( var x = 0; x < object.shadowCascadeArray.length; x ++ ) { + + this.__removeObject( object.shadowCascadeArray[ x ] ); + + } + + } + + } else if ( !( object instanceof THREE.Camera ) ) { + + this.__objectsRemoved.push( object ); + + // check if previously added + + var i = this.__objectsAdded.indexOf( object ); + + if ( i !== -1 ) { + + this.__objectsAdded.splice( i, 1 ); + + } + + } + + this.dispatchEvent( { type: 'objectRemoved', object: object } ); + object.dispatchEvent( { type: 'removedFromScene', scene: this } ); + + for ( var c = 0; c < object.children.length; c ++ ) { + + this.__removeObject( object.children[ c ] ); + + } + +}; + +THREE.Scene.prototype.clone = function ( object ) { + + if ( object === undefined ) object = new THREE.Scene(); + + THREE.Object3D.prototype.clone.call(this, object); + + if ( this.fog !== null ) object.fog = this.fog.clone(); + if ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone(); + + object.autoUpdate = this.autoUpdate; + object.matrixAutoUpdate = this.matrixAutoUpdate; + + return object; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Fog = function ( color, near, far ) { + + this.name = ''; + + this.color = new THREE.Color( color ); + + this.near = ( near !== undefined ) ? near : 1; + this.far = ( far !== undefined ) ? far : 1000; + +}; + +THREE.Fog.prototype.clone = function () { + + return new THREE.Fog( this.color.getHex(), this.near, this.far ); + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.FogExp2 = function ( color, density ) { + + this.name = ''; + + this.color = new THREE.Color( color ); + this.density = ( density !== undefined ) ? density : 0.00025; + +}; + +THREE.FogExp2.prototype.clone = function () { + + return new THREE.FogExp2( this.color.getHex(), this.density ); + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.CanvasRenderer = function ( parameters ) { + + console.log( 'THREE.CanvasRenderer', THREE.REVISION ); + + var smoothstep = THREE.Math.smoothstep; + + parameters = parameters || {}; + + var _this = this, + _renderData, _elements, _lights, + _projector = new THREE.Projector(), + + _canvas = parameters.canvas !== undefined + ? parameters.canvas + : document.createElement( 'canvas' ), + + _canvasWidth = _canvas.width, + _canvasHeight = _canvas.height, + _canvasWidthHalf = Math.floor( _canvasWidth / 2 ), + _canvasHeightHalf = Math.floor( _canvasHeight / 2 ), + + _context = _canvas.getContext( '2d', { + alpha: parameters.alpha === true + } ), + + _clearColor = new THREE.Color( 0x000000 ), + _clearAlpha = 0, + + _contextGlobalAlpha = 1, + _contextGlobalCompositeOperation = 0, + _contextStrokeStyle = null, + _contextFillStyle = null, + _contextLineWidth = null, + _contextLineCap = null, + _contextLineJoin = null, + _contextDashSize = null, + _contextGapSize = 0, + + _camera, + + _v1, _v2, _v3, _v4, + _v5 = new THREE.RenderableVertex(), + _v6 = new THREE.RenderableVertex(), + + _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, + _v4x, _v4y, _v5x, _v5y, _v6x, _v6y, + + _color = new THREE.Color(), + _color1 = new THREE.Color(), + _color2 = new THREE.Color(), + _color3 = new THREE.Color(), + _color4 = new THREE.Color(), + + _diffuseColor = new THREE.Color(), + _emissiveColor = new THREE.Color(), + + _lightColor = new THREE.Color(), + + _patterns = {}, + + _near, _far, + + _image, _uvs, + _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, + + _clipBox = new THREE.Box2(), + _clearBox = new THREE.Box2(), + _elemBox = new THREE.Box2(), + + _ambientLight = new THREE.Color(), + _directionalLights = new THREE.Color(), + _pointLights = new THREE.Color(), + + _vector3 = new THREE.Vector3(), // Needed for PointLight + _normal = new THREE.Vector3(), + _normalViewMatrix = new THREE.Matrix3(), + + _pixelMap, _pixelMapContext, _pixelMapImage, _pixelMapData, + _gradientMap, _gradientMapContext, _gradientMapQuality = 16; + + _pixelMap = document.createElement( 'canvas' ); + _pixelMap.width = _pixelMap.height = 2; + + _pixelMapContext = _pixelMap.getContext( '2d' ); + _pixelMapContext.fillStyle = 'rgba(0,0,0,1)'; + _pixelMapContext.fillRect( 0, 0, 2, 2 ); + + _pixelMapImage = _pixelMapContext.getImageData( 0, 0, 2, 2 ); + _pixelMapData = _pixelMapImage.data; + + _gradientMap = document.createElement( 'canvas' ); + _gradientMap.width = _gradientMap.height = _gradientMapQuality; + + _gradientMapContext = _gradientMap.getContext( '2d' ); + _gradientMapContext.translate( - _gradientMapQuality / 2, - _gradientMapQuality / 2 ); + _gradientMapContext.scale( _gradientMapQuality, _gradientMapQuality ); + + _gradientMapQuality --; // Fix UVs + + // dash+gap fallbacks for Firefox and everything else + + if ( _context.setLineDash === undefined ) { + + if ( _context.mozDash !== undefined ) { + + _context.setLineDash = function ( values ) { + + _context.mozDash = values[ 0 ] !== null ? values : null; + + } + + } else { + + _context.setLineDash = function () {} + + } + + } + + this.domElement = _canvas; + + this.devicePixelRatio = parameters.devicePixelRatio !== undefined + ? parameters.devicePixelRatio + : self.devicePixelRatio !== undefined + ? self.devicePixelRatio + : 1; + + this.autoClear = true; + this.sortObjects = true; + this.sortElements = true; + + this.info = { + + render: { + + vertices: 0, + faces: 0 + + } + + } + + // WebGLRenderer compatibility + + this.supportsVertexTextures = function () {}; + this.setFaceCulling = function () {}; + + this.setSize = function ( width, height, updateStyle ) { + + _canvasWidth = width * this.devicePixelRatio; + _canvasHeight = height * this.devicePixelRatio; + + _canvasWidthHalf = Math.floor( _canvasWidth / 2 ); + _canvasHeightHalf = Math.floor( _canvasHeight / 2 ); + + _canvas.width = _canvasWidth; + _canvas.height = _canvasHeight; + + if ( this.devicePixelRatio !== 1 && updateStyle !== false ) { + + _canvas.style.width = width + 'px'; + _canvas.style.height = height + 'px'; + + } + + _clipBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ), + _clipBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); + + _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); + _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); + + _contextGlobalAlpha = 1; + _contextGlobalCompositeOperation = 0; + _contextStrokeStyle = null; + _contextFillStyle = null; + _contextLineWidth = null; + _contextLineCap = null; + _contextLineJoin = null; + + }; + + this.setClearColor = function ( color, alpha ) { + + _clearColor.set( color ); + _clearAlpha = alpha !== undefined ? alpha : 1; + + _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); + _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); + + }; + + this.setClearColorHex = function ( hex, alpha ) { + + THREE.onwarning( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); + this.setClearColor( hex, alpha ); + + }; + + this.getMaxAnisotropy = function () { + + return 0; + + }; + + this.clear = function () { + + _context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf ); + + if ( _clearBox.empty() === false ) { + + _clearBox.intersect( _clipBox ); + _clearBox.expandByScalar( 2 ); + + if ( _clearAlpha < 1 ) { + + _context.clearRect( + _clearBox.min.x | 0, + _clearBox.min.y | 0, + ( _clearBox.max.x - _clearBox.min.x ) | 0, + ( _clearBox.max.y - _clearBox.min.y ) | 0 + ); + + } + + if ( _clearAlpha > 0 ) { + + setBlending( THREE.NormalBlending ); + setOpacity( 1 ); + + setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' ); + + _context.fillRect( + _clearBox.min.x | 0, + _clearBox.min.y | 0, + ( _clearBox.max.x - _clearBox.min.x ) | 0, + ( _clearBox.max.y - _clearBox.min.y ) | 0 + ); + + } + + _clearBox.makeEmpty(); + + } + + }; + + // compatibility + + this.clearColor = function () {}; + this.clearDepth = function () {}; + this.clearStencil = function () {}; + + this.render = function ( scene, camera ) { + + if ( camera instanceof THREE.Camera === false ) { + + THREE.onerror( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' ); + return; + + } + + if ( this.autoClear === true ) this.clear(); + + _context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf ); + + _this.info.render.vertices = 0; + _this.info.render.faces = 0; + + _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements ); + _elements = _renderData.elements; + _lights = _renderData.lights; + _camera = camera; + + _normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse ); + + /* DEBUG + setFillStyle( 'rgba( 0, 255, 255, 0.5 )' ); + _context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y ); + */ + + calculateLights(); + + for ( var e = 0, el = _elements.length; e < el; e ++ ) { + + var element = _elements[ e ]; + + var material = element.material; + + if ( material === undefined || material.visible === false ) continue; + + _elemBox.makeEmpty(); + + if ( element instanceof THREE.RenderableSprite ) { + + _v1 = element; + _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf; + + renderSprite( _v1, element, material ); + + } else if ( element instanceof THREE.RenderableLine ) { + + _v1 = element.v1; _v2 = element.v2; + + _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; + _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; + + _elemBox.setFromPoints( [ + _v1.positionScreen, + _v2.positionScreen + ] ); + + if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { + + renderLine( _v1, _v2, element, material ); + + } + + } else if ( element instanceof THREE.RenderableFace ) { + + _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; + + if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue; + if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue; + if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue; + + _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; + _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; + _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf; + + if ( material.overdraw > 0 ) { + + expand( _v1.positionScreen, _v2.positionScreen, material.overdraw ); + expand( _v2.positionScreen, _v3.positionScreen, material.overdraw ); + expand( _v3.positionScreen, _v1.positionScreen, material.overdraw ); + + } + + _elemBox.setFromPoints( [ + _v1.positionScreen, + _v2.positionScreen, + _v3.positionScreen + ] ); + + if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { + + renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material ); + + } + + } + + /* DEBUG + setLineWidth( 1 ); + setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' ); + _context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y ); + */ + + _clearBox.union( _elemBox ); + + } + + /* DEBUG + setLineWidth( 1 ); + setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' ); + _context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y ); + */ + + _context.setTransform( 1, 0, 0, 1, 0, 0 ); + + }; + + // + + function calculateLights() { + + _ambientLight.setRGB( 0, 0, 0 ); + _directionalLights.setRGB( 0, 0, 0 ); + _pointLights.setRGB( 0, 0, 0 ); + + for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { + + var light = _lights[ l ]; + var lightColor = light.color; + + if ( light instanceof THREE.AmbientLight ) { + + _ambientLight.add( lightColor ); + + } else if ( light instanceof THREE.DirectionalLight ) { + + // for sprites + + _directionalLights.add( lightColor ); + + } else if ( light instanceof THREE.PointLight ) { + + // for sprites + + _pointLights.add( lightColor ); + + } + + } + + } + + function calculateLight( position, normal, color ) { + + for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { + + var light = _lights[ l ]; + + _lightColor.copy( light.color ); + + if ( light instanceof THREE.DirectionalLight ) { + + var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize(); + + var amount = normal.dot( lightPosition ); + + if ( amount <= 0 ) continue; + + amount *= light.intensity; + + color.add( _lightColor.multiplyScalar( amount ) ); + + } else if ( light instanceof THREE.PointLight ) { + + var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ); + + var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() ); + + if ( amount <= 0 ) continue; + + amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 ); + + if ( amount == 0 ) continue; + + amount *= light.intensity; + + color.add( _lightColor.multiplyScalar( amount ) ); + + } + + } + + } + + function renderSprite( v1, element, material ) { + + setOpacity( material.opacity ); + setBlending( material.blending ); + + var scaleX = element.scale.x * _canvasWidthHalf; + var scaleY = element.scale.y * _canvasHeightHalf; + + var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite + _elemBox.min.set( v1.x - dist, v1.y - dist ); + _elemBox.max.set( v1.x + dist, v1.y + dist ); + + if ( material instanceof THREE.SpriteMaterial || + material instanceof THREE.ParticleSystemMaterial ) { // Backwards compatibility + + var texture = material.map; + + if ( texture !== null ) { + + if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { + + if ( texture.image !== undefined && texture.image.width > 0 ) { + + textureToPattern( texture ); + + } + + texture.addEventListener( 'update', onTextureUpdate ); + + } + + var pattern = _patterns[ texture.id ]; + + if ( pattern !== undefined ) { + + setFillStyle( pattern ); + + } else { + + setFillStyle( 'rgba( 0, 0, 0, 1 )' ); + + } + + // + + var bitmap = texture.image; + + var ox = bitmap.width * texture.offset.x; + var oy = bitmap.height * texture.offset.y; + + var sx = bitmap.width * texture.repeat.x; + var sy = bitmap.height * texture.repeat.y; + + var cx = scaleX / sx; + var cy = scaleY / sy; + + _context.save(); + _context.translate( v1.x, v1.y ); + if ( material.rotation !== 0 ) _context.rotate( material.rotation ); + _context.translate( - scaleX / 2, - scaleY / 2 ); + _context.scale( cx, cy ); + _context.translate( - ox, - oy ); + _context.fillRect( ox, oy, sx, sy ); + _context.restore(); + + } else { // no texture + + setFillStyle( material.color.getStyle() ); + + _context.save(); + _context.translate( v1.x, v1.y ); + if ( material.rotation !== 0 ) _context.rotate( material.rotation ); + _context.scale( scaleX, - scaleY ); + _context.fillRect( - 0.5, - 0.5, 1, 1 ); + _context.restore(); + + } + + } else if ( material instanceof THREE.SpriteCanvasMaterial ) { + + setStrokeStyle( material.color.getStyle() ); + setFillStyle( material.color.getStyle() ); + + _context.save(); + _context.translate( v1.x, v1.y ); + if ( material.rotation !== 0 ) _context.rotate( material.rotation ); + _context.scale( scaleX, scaleY ); + + material.program( _context ); + + _context.restore(); + + } + + /* DEBUG + setStrokeStyle( 'rgb(255,255,0)' ); + _context.beginPath(); + _context.moveTo( v1.x - 10, v1.y ); + _context.lineTo( v1.x + 10, v1.y ); + _context.moveTo( v1.x, v1.y - 10 ); + _context.lineTo( v1.x, v1.y + 10 ); + _context.stroke(); + */ + + } + + function renderLine( v1, v2, element, material ) { + + setOpacity( material.opacity ); + setBlending( material.blending ); + + _context.beginPath(); + _context.moveTo( v1.positionScreen.x, v1.positionScreen.y ); + _context.lineTo( v2.positionScreen.x, v2.positionScreen.y ); + + if ( material instanceof THREE.LineBasicMaterial ) { + + setLineWidth( material.linewidth ); + setLineCap( material.linecap ); + setLineJoin( material.linejoin ); + + if ( material.vertexColors !== THREE.VertexColors ) { + + setStrokeStyle( material.color.getStyle() ); + + } else { + + var colorStyle1 = element.vertexColors[0].getStyle(); + var colorStyle2 = element.vertexColors[1].getStyle(); + + if ( colorStyle1 === colorStyle2 ) { + + setStrokeStyle( colorStyle1 ); + + } else { + + try { + + var grad = _context.createLinearGradient( + v1.positionScreen.x, + v1.positionScreen.y, + v2.positionScreen.x, + v2.positionScreen.y + ); + grad.addColorStop( 0, colorStyle1 ); + grad.addColorStop( 1, colorStyle2 ); + + } catch ( exception ) { + + grad = colorStyle1; + + } + + setStrokeStyle( grad ); + + } + + } + + _context.stroke(); + _elemBox.expandByScalar( material.linewidth * 2 ); + + } else if ( material instanceof THREE.LineDashedMaterial ) { + + setLineWidth( material.linewidth ); + setLineCap( material.linecap ); + setLineJoin( material.linejoin ); + setStrokeStyle( material.color.getStyle() ); + setDashAndGap( material.dashSize, material.gapSize ); + + _context.stroke(); + + _elemBox.expandByScalar( material.linewidth * 2 ); + + setDashAndGap( null, null ); + + } + + } + + function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) { + + _this.info.render.vertices += 3; + _this.info.render.faces ++; + + setOpacity( material.opacity ); + setBlending( material.blending ); + + _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y; + _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y; + _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y; + + drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y ); + + if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial || material instanceof THREE.MeshPhysicalMaterial ) && material.map === null ) { + + _diffuseColor.copy( material.color ); + _emissiveColor.copy( material.emissive ); + + if ( material.vertexColors === THREE.FaceColors ) { + + _diffuseColor.multiply( element.color ); + + } + + if ( material.wireframe === false && material.shading === THREE.SmoothShading && element.vertexNormalsLength === 3 ) { + + _color1.copy( _ambientLight ); + _color2.copy( _ambientLight ); + _color3.copy( _ambientLight ); + + calculateLight( element.v1.positionWorld, element.vertexNormalsModel[ 0 ], _color1 ); + calculateLight( element.v2.positionWorld, element.vertexNormalsModel[ 1 ], _color2 ); + calculateLight( element.v3.positionWorld, element.vertexNormalsModel[ 2 ], _color3 ); + + _color1.multiply( _diffuseColor ).add( _emissiveColor ); + _color2.multiply( _diffuseColor ).add( _emissiveColor ); + _color3.multiply( _diffuseColor ).add( _emissiveColor ); + _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); + + _image = getGradientTexture( _color1, _color2, _color3, _color4 ); + + clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); + + } else { + + _color.copy( _ambientLight ); + + calculateLight( element.centroidModel, element.normalModel, _color ); + + _color.multiply( _diffuseColor ).add( _emissiveColor ); + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } + + } else if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) { + + if ( material.map !== null ) { + + if ( material.map.mapping instanceof THREE.UVMapping ) { + + _uvs = element.uvs[ 0 ]; + patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map ); + + } + + + } else if ( material.envMap !== null ) { + + if ( material.envMap.mapping instanceof THREE.SphericalReflectionMapping ) { + + _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); + _uv1x = 0.5 * _normal.x + 0.5; + _uv1y = 0.5 * _normal.y + 0.5; + + _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); + _uv2x = 0.5 * _normal.x + 0.5; + _uv2y = 0.5 * _normal.y + 0.5; + + _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); + _uv3x = 0.5 * _normal.x + 0.5; + _uv3y = 0.5 * _normal.y + 0.5; + + patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap ); + + }/* else if ( material.envMap.mapping === THREE.SphericalRefractionMapping ) { + + + + }*/ + + + } else { + + _color.copy( material.color ); + + if ( material.vertexColors === THREE.FaceColors ) { + + _color.multiply( element.color ); + + } + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } + + } else if ( material instanceof THREE.MeshDepthMaterial ) { + + _near = _camera.near; + _far = _camera.far; + + _color1.r = _color1.g = _color1.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _near, _far ); + _color2.r = _color2.g = _color2.b = 1 - smoothstep( v2.positionScreen.z * v2.positionScreen.w, _near, _far ); + _color3.r = _color3.g = _color3.b = 1 - smoothstep( v3.positionScreen.z * v3.positionScreen.w, _near, _far ); + _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); + + _image = getGradientTexture( _color1, _color2, _color3, _color4 ); + + clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); + + } else if ( material instanceof THREE.MeshNormalMaterial ) { + + if ( material.shading === THREE.FlatShading ) { + + _normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix ); + + _color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + material.wireframe === true + ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) + : fillPath( _color ); + + } else if ( material.shading === THREE.SmoothShading ) { + + _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); + _color1.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); + _color2.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); + _color3.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); + + _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); + + _image = getGradientTexture( _color1, _color2, _color3, _color4 ); + + clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); + + } + + } + + } + + // + + function drawTriangle( x0, y0, x1, y1, x2, y2 ) { + + _context.beginPath(); + _context.moveTo( x0, y0 ); + _context.lineTo( x1, y1 ); + _context.lineTo( x2, y2 ); + _context.closePath(); + + } + + function strokePath( color, linewidth, linecap, linejoin ) { + + setLineWidth( linewidth ); + setLineCap( linecap ); + setLineJoin( linejoin ); + setStrokeStyle( color.getStyle() ); + + _context.stroke(); + + _elemBox.expandByScalar( linewidth * 2 ); + + } + + function fillPath( color ) { + + setFillStyle( color.getStyle() ); + _context.fill(); + + } + + function onTextureUpdate ( event ) { + + textureToPattern( event.target ); + + } + + function textureToPattern( texture ) { + + var repeatX = texture.wrapS === THREE.RepeatWrapping; + var repeatY = texture.wrapT === THREE.RepeatWrapping; + + var image = texture.image; + + var canvas = document.createElement( 'canvas' ); + canvas.width = image.width; + canvas.height = image.height; + + var context = canvas.getContext( '2d' ); + context.setTransform( 1, 0, 0, - 1, 0, image.height ); + context.drawImage( image, 0, 0 ); + + _patterns[ texture.id ] = _context.createPattern( + canvas, repeatX === true && repeatY === true + ? 'repeat' + : repeatX === true && repeatY === false + ? 'repeat-x' + : repeatX === false && repeatY === true + ? 'repeat-y' + : 'no-repeat' + ); + + } + + function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) { + + if ( texture instanceof THREE.DataTexture ) return; + + if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { + + if ( texture.image !== undefined && texture.image.width > 0 ) { + + textureToPattern( texture ); + + } + + texture.addEventListener( 'update', onTextureUpdate ); + + } + + var pattern = _patterns[ texture.id ]; + + if ( pattern !== undefined ) { + + setFillStyle( pattern ); + + } else { + + setFillStyle( 'rgba(0,0,0,1)' ); + _context.fill(); + + return; + + } + + // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + + var a, b, c, d, e, f, det, idet, + offsetX = texture.offset.x / texture.repeat.x, + offsetY = texture.offset.y / texture.repeat.y, + width = texture.image.width * texture.repeat.x, + height = texture.image.height * texture.repeat.y; + + u0 = ( u0 + offsetX ) * width; + v0 = ( v0 + offsetY ) * height; + + u1 = ( u1 + offsetX ) * width; + v1 = ( v1 + offsetY ) * height; + + u2 = ( u2 + offsetX ) * width; + v2 = ( v2 + offsetY ) * height; + + x1 -= x0; y1 -= y0; + x2 -= x0; y2 -= y0; + + u1 -= u0; v1 -= v0; + u2 -= u0; v2 -= v0; + + det = u1 * v2 - u2 * v1; + + if ( det === 0 ) return; + + idet = 1 / det; + + a = ( v2 * x1 - v1 * x2 ) * idet; + b = ( v2 * y1 - v1 * y2 ) * idet; + c = ( u1 * x2 - u2 * x1 ) * idet; + d = ( u1 * y2 - u2 * y1 ) * idet; + + e = x0 - a * u0 - c * v0; + f = y0 - b * u0 - d * v0; + + _context.save(); + _context.transform( a, b, c, d, e, f ); + _context.fill(); + _context.restore(); + + } + + function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) { + + // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + + var a, b, c, d, e, f, det, idet, + width = image.width - 1, + height = image.height - 1; + + u0 *= width; v0 *= height; + u1 *= width; v1 *= height; + u2 *= width; v2 *= height; + + x1 -= x0; y1 -= y0; + x2 -= x0; y2 -= y0; + + u1 -= u0; v1 -= v0; + u2 -= u0; v2 -= v0; + + det = u1 * v2 - u2 * v1; + + idet = 1 / det; + + a = ( v2 * x1 - v1 * x2 ) * idet; + b = ( v2 * y1 - v1 * y2 ) * idet; + c = ( u1 * x2 - u2 * x1 ) * idet; + d = ( u1 * y2 - u2 * y1 ) * idet; + + e = x0 - a * u0 - c * v0; + f = y0 - b * u0 - d * v0; + + _context.save(); + _context.transform( a, b, c, d, e, f ); + _context.clip(); + _context.drawImage( image, 0, 0 ); + _context.restore(); + + } + + function getGradientTexture( color1, color2, color3, color4 ) { + + // http://mrdoob.com/blog/post/710 + + _pixelMapData[ 0 ] = ( color1.r * 255 ) | 0; + _pixelMapData[ 1 ] = ( color1.g * 255 ) | 0; + _pixelMapData[ 2 ] = ( color1.b * 255 ) | 0; + + _pixelMapData[ 4 ] = ( color2.r * 255 ) | 0; + _pixelMapData[ 5 ] = ( color2.g * 255 ) | 0; + _pixelMapData[ 6 ] = ( color2.b * 255 ) | 0; + + _pixelMapData[ 8 ] = ( color3.r * 255 ) | 0; + _pixelMapData[ 9 ] = ( color3.g * 255 ) | 0; + _pixelMapData[ 10 ] = ( color3.b * 255 ) | 0; + + _pixelMapData[ 12 ] = ( color4.r * 255 ) | 0; + _pixelMapData[ 13 ] = ( color4.g * 255 ) | 0; + _pixelMapData[ 14 ] = ( color4.b * 255 ) | 0; + + _pixelMapContext.putImageData( _pixelMapImage, 0, 0 ); + _gradientMapContext.drawImage( _pixelMap, 0, 0 ); + + return _gradientMap; + + } + + // Hide anti-alias gaps + + function expand( v1, v2, pixels ) { + + var x = v2.x - v1.x, y = v2.y - v1.y, + det = x * x + y * y, idet; + + if ( det === 0 ) return; + + idet = pixels / Math.sqrt( det ); + + x *= idet; y *= idet; + + v2.x += x; v2.y += y; + v1.x -= x; v1.y -= y; + + } + + // Context cached methods. + + function setOpacity( value ) { + + if ( _contextGlobalAlpha !== value ) { + + _context.globalAlpha = value; + _contextGlobalAlpha = value; + + } + + } + + function setBlending( value ) { + + if ( _contextGlobalCompositeOperation !== value ) { + + if ( value === THREE.NormalBlending ) { + + _context.globalCompositeOperation = 'source-over'; + + } else if ( value === THREE.AdditiveBlending ) { + + _context.globalCompositeOperation = 'lighter'; + + } else if ( value === THREE.SubtractiveBlending ) { + + _context.globalCompositeOperation = 'darker'; + + } + + _contextGlobalCompositeOperation = value; + + } + + } + + function setLineWidth( value ) { + + if ( _contextLineWidth !== value ) { + + _context.lineWidth = value; + _contextLineWidth = value; + + } + + } + + function setLineCap( value ) { + + // "butt", "round", "square" + + if ( _contextLineCap !== value ) { + + _context.lineCap = value; + _contextLineCap = value; + + } + + } + + function setLineJoin( value ) { + + // "round", "bevel", "miter" + + if ( _contextLineJoin !== value ) { + + _context.lineJoin = value; + _contextLineJoin = value; + + } + + } + + function setStrokeStyle( value ) { + + if ( _contextStrokeStyle !== value ) { + + _context.strokeStyle = value; + _contextStrokeStyle = value; + + } + + } + + function setFillStyle( value ) { + + if ( _contextFillStyle !== value ) { + + _context.fillStyle = value; + _contextFillStyle = value; + + } + + } + + function setDashAndGap( dashSizeValue, gapSizeValue ) { + + if ( _contextDashSize !== dashSizeValue || _contextGapSize !== gapSizeValue ) { + + _context.setLineDash( [ dashSizeValue, gapSizeValue ] ); + _contextDashSize = dashSizeValue; + _contextGapSize = gapSizeValue; + + } + + } + +}; + +/** + * Shader chunks for WebLG Shader library + * + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author bhouston / http://clara.io/ + */ + +THREE.ShaderChunk = { + + // FOG + + common: [ + + "#define PI 3.14159", + "#define PI2 6.28318", + "#define LOG2 1.442695", + "#define ENCODING_Linear 3000", + "#define ENCODING_sRGB 3001", + "#define ENCODING_RGBE 3002", + "#define ENCODING_RGBM7 3004", + "#define ENCODING_RGBM16 3005", + "#define SPECULAR_COEFF 0.18", + "float square( float a ) { return a*a; }", + "vec2 square( vec2 a ) { return vec2( a.x*a.x, a.y*a.y ); }", + "vec3 square( vec3 a ) { return vec3( a.x*a.x, a.y*a.y, a.z*a.z ); }", + "vec4 square( vec4 a ) { return vec4( a.x*a.x, a.y*a.y, a.z*a.z, a.w*a.w ); }", + "float saturate( float a ) { return clamp( a, 0.0, 1.0 ); }", + "vec2 saturate( vec2 a ) { return clamp( a, 0.0, 1.0 ); }", + "vec3 saturate( vec3 a ) { return clamp( a, 0.0, 1.0 ); }", + "vec4 saturate( vec4 a ) { return clamp( a, 0.0, 1.0 ); }", + "float average( float a ) { return a; }", + "float average( vec2 a ) { return ( a.x + a.y) * 0.5; }", + "float average( vec3 a ) { return ( a.x + a.y + a.z) * 0.3333333333; }", + "float average( vec4 a ) { return ( a.x + a.y + a.z + a.w) * 0.25; }", + "float whiteCompliment( float a ) { return saturate( 1.0 - a ); }", + "vec2 whiteCompliment( vec2 a ) { return saturate( vec2(1.0) - a ); }", + "vec3 whiteCompliment( vec3 a ) { return saturate( vec3(1.0) - a ); }", + "vec4 whiteCompliment( vec4 a ) { return saturate( vec4(1.0) - a ); }", + "vec3 projectOnPlane( vec3 point, vec3 pointOnPlane, vec3 planeNormal) {", + "float distance = dot( planeNormal, point-pointOnPlane );", + "return point - distance * planeNormal;", + "}", + "float sideOfPlane( vec3 point, vec3 pointOnPlane, vec3 planeNormal ) {", + "return sign( dot( point - pointOnPlane, planeNormal ) );", + "}", + "vec2 applyUVOffsetRepeat( vec2 uv, vec4 offsetRepeat ) {", + "return uv * offsetRepeat.zw + offsetRepeat.xy;", + "}", + "vec3 linePlaneIntersect( vec3 pointOnLine, vec3 lineDirection, vec3 pointOnPlane, vec3 planeNormal ) {", + "return pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) );", + "}", + "vec4 applyGainBrightness( vec4 texel, vec4 gainBrightnessCoeff ) {", + "if( gainBrightnessCoeff.w < 0.0 ) {", + "texel.xyz = whiteCompliment( texel.xyz );", + "}", + "texel.xyz = ( texel.xyz - vec3( gainBrightnessCoeff.x ) ) * gainBrightnessCoeff.y + vec3( gainBrightnessCoeff.z + gainBrightnessCoeff.x );", + "return texel;", + "}", + "vec4 texelDecode( vec4 texel, int encoding ) {", + + "if( encoding == 3001 ) {", // sRGB + "texel = vec4( pow( max( texel.xyz, vec3( 0.0 ) ), vec3( 2.2 ) ), texel.w );", + "}", + + "else if( encoding == 3002 ) {", // RGBE / Radiance + "texel = vec4( texel.xyz * pow( 2.0, texel.w*256.0 - 128.0 ), 1.0 );", + "}", + + // TODO LogLUV decoding. + + "else if( encoding == 3004 ) {", // RGBM 7.0 / Marmoset + "texel = vec4( texel.xyz * texel.w * 7.0, 1.0 );", + "}", + + "else if( encoding == 3005 ) {", // RGBM 16 + "texel = vec4( texel.xyz * texel.w * 16.0, 1.0 );", + "}", + + "return texel;", + "}", + ].join("\n"), + + // FOG + + fog_pars_fragment: [ + + "#ifdef USE_FOG", + + "uniform vec3 fogColor;", + + "#ifdef FOG_EXP2", + + "uniform float fogDensity;", + + "#else", + + "uniform float fogNear;", + "uniform float fogFar;", + + "#endif", + + "#endif" + + ].join("\n"), + + fog_fragment: [ + + "#ifdef USE_FOG", + + "float depth = gl_FragCoord.z / gl_FragCoord.w;", + + "#ifdef FOG_EXP2", + + "float fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );", + "fogFactor = 1.0 - saturate( fogFactor );", + + "#else", + + "float fogFactor = smoothstep( fogNear, fogFar, depth );", + + "#endif", + + "gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );", + + "#endif" + + ].join("\n"), + + // DIFFUSE ENVIRONMENT MAP + + diffuseenvmap_pars_fragment: [ + + "#if defined( USE_DIFFUSEENVMAP )", + + "uniform samplerCube diffuseEnvMap;", + "uniform int diffuseEnvEncoding;", + + "#endif" + + ].join("\n"), + + // ENVIRONMENT MAP + + envmap_pars_fragment: [ + + "#if defined( USE_DIFFUSEENVMAP ) || defined( USE_ENVMAP )", + + "uniform float flipEnvMap;", + + "#endif", + + "#ifdef USE_ENVMAP", + + "uniform float reflectivity;", + "uniform samplerCube envMap;", + "uniform int combine;", + "uniform int envEncoding;", + + "#endif" + + ].join("\n"), + + envmap_fragment: [ + + "#if defined( USE_ENVMAP ) && ! defined( PHYSICAL )", + + "vec3 worldNormal = vec3( normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz ) );", + "vec3 worldView = -vec3( normalize( ( vec4( viewDirection, 0.0 ) * viewMatrix ).xyz ) );", + + "vec3 reflectVec = reflect( worldView, worldNormal );", + + "#ifdef DOUBLE_SIDED", + + "float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + + "vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", + + "#else", + + "vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", + + "#endif", + + "cubeColor = texelDecode( cubeColor, envEncoding );", + + "float fresnelReflectivity = saturate( reflectivity );", + + "if ( combine == 1 ) {", + + "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, fresnelReflectivity );", + + "} else if ( combine == 2 ) {", + + "gl_FragColor.xyz += cubeColor.xyz * fresnelReflectivity;", + + "} else {", + + "gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, fresnelReflectivity );", + + "}", + + "#endif" + + ].join("\n"), + + worldpos_vertex : [ + + "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )", + + "#ifdef USE_SKINNING", + + "vec4 worldPosition = modelMatrix * skinned;", + + "#endif", + + "#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", + + "vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );", + + "#endif", + + "#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", + + "vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", + + "#endif", + + "#endif" + + ].join("\n"), + + // COLOR MAP (particles) + + map_particle_pars_fragment: [ + + "#ifdef USE_MAP", + + "uniform sampler2D map;", + + "#endif" + + ].join("\n"), + + + map_particle_fragment: [ + + "#ifdef USE_MAP", + + "gl_FragColor = gl_FragColor * texelDecode( texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) ), ENCODING_sRGB );", + + "#endif" + + ].join("\n"), + + // COLOR MAP (triangles) + + map_pars_vertex: [ + + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )", + + "varying vec2 vUv;", + + "#endif" + + ].join("\n"), + + map_pars_fragment: [ + + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )", + + "varying vec2 vUv;", + "uniform vec4 offsetRepeat;", + "uniform vec4 gainBrightness;", + + "#endif", + + "#ifdef USE_MAP", + + "uniform sampler2D map;", + + "#endif" + + ].join("\n"), + + map_vertex: [ + + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )", + + "vUv = uv;", + + "#endif" + + ].join("\n"), + + map_fragment: [ + + "#if defined( USE_MAP ) || defined( USE_FALLOFFMAP )", + + "vec2 vUvLocal = applyUVOffsetRepeat( vUv, offsetRepeat );", + + "#endif", + + "#ifdef USE_MAP", + + "vec4 texelColor = clamp( applyGainBrightness( texelDecode( texture2D( map, vUvLocal ), ENCODING_sRGB ), gainBrightness ), vec4(0.0), vec4(1.0) );", + + "gl_FragColor = gl_FragColor * texelColor;", + + "#if defined( PHYSICAL ) || defined( PHONG )", + + "diffuseColor *= texelColor.xyz;", + + "#endif", // PHYSICAL + + "#endif" + + ].join("\n"), + + // FALLOFF MAP + + falloffmap_pars_fragment: [ + + "#ifdef USE_FALLOFFMAP", + + "uniform sampler2D falloffMap;", + + "#endif" + + ].join("\n"), + + // OPACITY MAP + + opacitymap_pars_fragment: [ + + "#ifdef USE_OPACITYMAP", + + "uniform sampler2D opacityMap;", + "uniform vec4 opacityOffsetRepeat;", + "uniform vec4 opacityGainBrightness;", + + "#endif" + + ].join("\n"), + + + opacitymap_fragment: [ + + "#ifdef USE_OPACITYMAP", + + "vec2 vOpacityUv = applyUVOffsetRepeat( vUv, opacityOffsetRepeat );", + "vec4 texelOpacity = applyGainBrightness( texture2D( opacityMap, vOpacityUv ), opacityGainBrightness );", + + "gl_FragColor.w = clamp( gl_FragColor.w * texelOpacity.r, 0.0, 1.0 );", + + "#endif" + + ].join("\n"), + + // TRANSLUCENCY MAP + + translucencymap_pars_fragment: [ + + "#ifdef USE_TRANSLUCENCYMAP", + + "uniform sampler2D translucencyMap;", + "uniform vec4 translucencyOffsetRepeat;", + "uniform vec4 translucencyGainBrightness;", + + "#endif" + + ].join("\n"), + + translucencymap_fragment: [ + + "#ifdef USE_TRANSLUCENCYMAP", + + "vec2 vTranslucencyUv = applyUVOffsetRepeat( vUv, translucencyOffsetRepeat );", + "vec4 texelTranslucency = applyGainBrightness( texture2D( translucencyMap, vTranslucencyUv ), translucencyGainBrightness );", + + "translucencyColor.xyz = clamp( translucencyColor.xyz * texelTranslucency.xyz, vec3( 0.0 ), vec3( 1.0 ) );", + + "#endif" + + ].join("\n"), + + // LIGHT MAP + + lightmap_pars_fragment: [ + + "#if defined( USE_LIGHTMAP ) || defined( USE_EMISSIVEMAP )", + + "varying vec2 vUv2;", + + "#endif", + + "#if defined( USE_LIGHTMAP )", + + "uniform sampler2D lightMap;", + + "#endif", + + "#if defined( USE_EMISSIVEMAP )", + + "uniform sampler2D emissiveMap;", + + "#endif" + + ].join("\n"), + + lightmap_pars_vertex: [ + + "#if defined( USE_LIGHTMAP ) || defined( USE_EMISSIVEMAP )", + + "varying vec2 vUv2;", + + "#endif" + + ].join("\n"), + + lightmap_fragment: [ + + "#ifdef USE_LIGHTMAP", + + //"gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );", + + "#endif" + + ].join("\n"), + + lightmap_vertex: [ + + "#if defined( USE_LIGHTMAP ) || defined( USE_EMISSIVEMAP )", + + "vUv2 = uv2;", + + "#endif" + + ].join("\n"), + + + // BUMP MAP + + bumpmap_pars_fragment: [ + + "#ifdef USE_BUMPMAP", + + "uniform sampler2D bumpMap;", + "uniform vec4 bumpOffsetRepeat;", + "uniform float bumpScale;", + + // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen + // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html + + // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2) + + "vec2 dHdxy_fwd() {", + + "#ifdef GL_OES_standard_derivatives", + + "vec2 vBumpUv = applyUVOffsetRepeat( vUv, bumpOffsetRepeat );", + + "vec2 dSTdx = dFdx( vBumpUv );", + "vec2 dSTdy = dFdy( vBumpUv );", + + "float Hll = bumpScale * texture2D( bumpMap, vBumpUv ).x;", + "float dBx = bumpScale * texture2D( bumpMap, vBumpUv + dSTdx ).x - Hll;", + "float dBy = bumpScale * texture2D( bumpMap, vBumpUv + dSTdy ).x - Hll;", + + "return vec2( dBx, dBy );", + + "#else", + + "return vec2( 0.0, 0.0 );", + + "#endif", + + "}", + + "vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {", + + "#ifdef GL_OES_standard_derivatives", + + "vec3 vSigmaX = dFdx( surf_pos );", + "vec3 vSigmaY = dFdy( surf_pos );", + "vec3 vN = surf_norm;", // normalized + + "vec3 R1 = cross( vSigmaY, vN );", + "vec3 R2 = cross( vN, vSigmaX );", + + "float fDet = dot( vSigmaX, R1 );", + + "vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );", + "return normalize( abs( fDet ) * surf_norm - vGrad );", + + "#else", + + "return surf_norm;", + + "#endif", + + "}", + + "#endif" + + ].join("\n"), + + // LIGHT ATTENUATION function + + lightattenuation_func_fragment: [ + + "float calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {", + "if ( decayExponent > 0.0 && cutoffDistance > 0.0 ) {", + "return pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );", + "}", + "else if ( decayExponent < 0.0 ) {", + // this is based upon UE4 light fall as described on page 11 of: + // https://de45xmedrsdbp.cloudfront.net/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf + "float numerator = 1.0;", + "if( cutoffDistance > 0.0 ) {", + "numerator = ( saturate( 1.0 - pow( lightDistance / cutoffDistance, 4.0 ) ) );", + "numerator *= numerator;", + "} ", + "return numerator / ( ( lightDistance * lightDistance ) + 1.0 );", + "}", + "else {", + "return 1.0;", + "}", + + /*"float distanceAttenuation = 1.0 / pow( max( lightDistance, 0.0 ), decayExponent );", + "if ( cutoffDistance > 0.0 ) {", + "distanceAttenuation *= 1.0 - min( lightDistance / cutoffDistance, 1.0 );", + "}", + "return distanceAttenuation;",*/ + "}", + + + ].join("\n"), + + // NORMAL MAP + + normalmap_pars_fragment: [ + + "#ifdef USE_NORMALMAP", + + "uniform sampler2D normalMap;", + "uniform vec4 normalOffsetRepeat;", + "uniform vec2 normalScale;", + + // Per-Pixel Tangent Space Normal Mapping + // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html + + "vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {", + + "#ifdef GL_OES_standard_derivatives", + + "vec2 vNormalUv = applyUVOffsetRepeat( vUv, normalOffsetRepeat );", + + "vec3 q0 = dFdx( eye_pos.xyz );", + "vec3 q1 = dFdy( eye_pos.xyz );", + "vec2 st0 = dFdx( vNormalUv.st );", + "vec2 st1 = dFdy( vNormalUv.st );", + + "vec3 S = normalize( q0 * st1.t - q1 * st0.t );", + "vec3 T = normalize( -q0 * st1.s + q1 * st0.s );", + "vec3 N = normalize( surf_norm );", + + "vec3 mapN = texture2D( normalMap, vNormalUv ).xyz * 2.0 - 1.0;", + "mapN.xy = normalScale * mapN.xy;", + "mat3 tsn = mat3( S, T, N );", + "return normalize( tsn * mapN );", + + "#else", + + "return surf_norm;", + + "#endif", + + "}", + + "#endif" + + ].join("\n"), + + // ANISOTROPY MAP + + anisotropymap_pars_fragment: [ + + "#ifdef USE_ANISOTROPYMAP", + + "uniform sampler2D anisotropyMap;", + "uniform vec4 anisotropyGainBrightness;", + "uniform vec4 anisotropyOffsetRepeat;", + + "#endif" + ].join("\n"), + + anisotropymap_fragment: [ + + "#ifdef USE_ANISOTROPYMAP", + + "vec2 vAnisotropyUv = applyUVOffsetRepeat( vUv, anisotropyOffsetRepeat );", + + "#else", + + "#ifdef ANISOTROPY", + + "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_REFLECTIVITYMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALLICMAP ) || defined( USE_OPACITYMAP ) || defined( USE_FALLOFFMAP ) || defined( USE_TRANSLUCENCYMAP ) || defined( USE_ANISOTROPYMAP ) || defined( USE_ANISOTROPYROTATIONMAP )", + + "vec2 vAnisotropyUv = vUv;", + + "#else", + + "vec2 vAnisotropyUv = vec2( 0, 0 );", + + "#endif", + + "#endif", + + "#endif", + + "float anisotropyStrength = anisotropy;", + + "#ifdef USE_ANISOTROPYMAP", + + "vec4 texelAnisotropy = applyGainBrightness( texture2D( anisotropyMap, vAnisotropyUv ), anisotropyGainBrightness );", + "anisotropyStrength = clamp( anisotropyStrength + texelAnisotropy.r, -1.0, 1.0 );", + + "#endif" + + ].join("\n"), + + // ANISOTROPY ROTATION MAP + + anisotropyrotationmap_pars_fragment: [ + + "#ifdef USE_ANISOTROPYROTATIONMAP", + + "uniform sampler2D anisotropyRotationMap;", + "uniform vec4 anisotropyRotationGainBrightness;", + "uniform vec4 anisotropyRotationOffsetRepeat;", + + "#endif" + + ].join("\n"), + + anisotropyrotationmap_fragment: [ + + "float anisotropyRotationStrength = anisotropyRotation;", + + "#ifdef USE_ANISOTROPYROTATIONMAP", + + "vec2 vAnisotropyRotationUv = applyUVOffsetRepeat( vUv, anisotropyRotationOffsetRepeat );", + "vec4 texelAnisotropyRotation = applyGainBrightness( texture2D( anisotropyRotationMap, vAnisotropyRotationUv ), anisotropyRotationGainBrightness );", + "anisotropyRotationStrength += texelAnisotropyRotation.r;", + + "#endif" + + ].join("\n"), + + // METALLIC MAP + + metallicmap_pars_fragment: [ + + "#ifdef USE_METALLICMAP", + + "uniform sampler2D metallicMap;", + "uniform vec4 metallicGainBrightness;", + "uniform vec4 metallicOffsetRepeat;", + + "#endif" + + ].join("\n"), + + metallicmap_fragment: [ + + "float metallicStrength = metallic;", + + "#ifdef USE_METALLICMAP", + + "vec2 vMetallicUv = applyUVOffsetRepeat( vUv, metallicOffsetRepeat );", + "vec4 texelMetallic = applyGainBrightness( texture2D( metallicMap, vMetallicUv ), metallicGainBrightness );", + "metallicStrength = clamp( metallicStrength * texelMetallic.r, 0.0, 1.0 );", + + "#endif" + + ].join("\n"), + + // ROUGHNESS MAP + + roughnessmap_pars_fragment: [ + + "#ifdef USE_ROUGHNESSMAP", + + "uniform sampler2D roughnessMap;", + "uniform vec4 roughnessOffsetRepeat;", + "uniform vec4 roughnessGainBrightness;", + + "#endif" + + ].join("\n"), + + roughnessmap_fragment: [ + + "float roughnessStrength = roughness;", + + "#ifdef USE_ROUGHNESSMAP", + + "vec2 vRoughnessUv = applyUVOffsetRepeat( vUv, roughnessOffsetRepeat );", + "vec4 texelRoughness = applyGainBrightness( texture2D( roughnessMap, vRoughnessUv ), roughnessGainBrightness );", + "roughnessStrength = clamp( roughnessStrength * texelRoughness.r, 0.0, 1.0 );", + + "#endif" + + ].join("\n"), + + // SPECULAR MAP + + specularmap_pars_fragment: [ + + "#ifdef USE_SPECULARMAP", + + "uniform sampler2D specularMap;", + "uniform vec4 specularGainBrightness;", + "uniform vec4 specularOffsetRepeat;", + + "#endif" + + ].join("\n"), + + specularmap_fragment: [ + + "#ifdef PHYSICAL", + "vec3 specularColor = specular;", + "#else", + "float specularStrength = 1.0;", + "#endif", + + "#ifdef USE_SPECULARMAP", + + "vec2 vSpecularUv = applyUVOffsetRepeat( vUv, specularOffsetRepeat );", + "vec4 texelSpecular = applyGainBrightness( texelDecode( texture2D( specularMap, vSpecularUv ), ENCODING_sRGB ), specularGainBrightness );", + + "#ifdef PHYSICAL", + "specularColor.rgb = clamp( specularColor.rgb * texelSpecular.rgb, vec3( 0.0 ), vec3( 1.0 ) );", + "#else", + "specularStrength = clamp( specularStrength * texelSpecular.r, 0.0, 1.0 );", + "#endif", + + "#endif", + + ].join("\n"), + + // LIGHTS LAMBERT + + lights_lambert_pars_vertex: [ + + "uniform vec3 ambient;", + "uniform vec3 diffuse;", + "uniform vec3 emissive;", + + "uniform vec3 ambientLightColor;", + + "#if MAX_DIR_LIGHTS > 0", + + "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", + "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", + "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDecayExponent[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#if MAX_AREA_LIGHTS > 0", + + "uniform vec3 areaLightColor[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightPosition[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightWidth[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightHeight[ MAX_AREA_LIGHTS ];", + "uniform float areaLightDistance[ MAX_AREA_LIGHTS ];", + "uniform float areaLightDecayExponent[ MAX_AREA_LIGHTS ];", + + "#endif", + + "#ifdef WRAP_AROUND", + + "uniform vec3 wrapRGB;", + + "#endif" + + ].join("\n"), + + lights_lambert_vertex: [ + + "vLightFront = vec3( 0.0 );", + + "#ifdef DOUBLE_SIDED", + + "vLightBack = vec3( 0.0 );", + + "#endif", + + "transformedNormal = normalize( transformedNormal );", + + "#if MAX_DIR_LIGHTS > 0", + + "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", + "vec3 dirVector = normalize( lDirection.xyz );", + + "float dotProduct = dot( transformedNormal, dirVector );", + "vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );", + + "#ifdef DOUBLE_SIDED", + + "vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + + "#ifdef WRAP_AROUND", + + "vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", + + "#endif", + + "#endif", + + "#ifdef WRAP_AROUND", + + "vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", + "directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );", + + "#ifdef DOUBLE_SIDED", + + "directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );", + + "#endif", + + "#endif", + + "vLightFront += directionalLightColor[ i ] * directionalLightWeighting;", + + "#ifdef DOUBLE_SIDED", + + "vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;", + + "#endif", + + "}", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz - mvPosition.xyz;", + + "float distanceAttenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );", + + "lVector = normalize( lVector );", + "float dotProduct = dot( transformedNormal, lVector );", + + "vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );", + + "#ifdef DOUBLE_SIDED", + + "vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + + "#ifdef WRAP_AROUND", + + "vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", + + "#endif", + + "#endif", + + "#ifdef WRAP_AROUND", + + "vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", + "pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );", + + "#ifdef DOUBLE_SIDED", + + "pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );", + + "#endif", + + "#endif", + + "vLightFront += pointLightColor[ i ] * pointLightWeighting * distanceAttenuation;", + + "#ifdef DOUBLE_SIDED", + + "vLightBack += pointLightColor[ i ] * pointLightWeightingBack * distanceAttenuation;", + + "#endif", + + "}", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz - mvPosition.xyz;", + + "float distanceAttenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );", + + "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );", + + "if ( spotEffect > spotLightAngleCos[ i ] ) {", + + "spotEffect = pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] );", + + "lVector = normalize( lVector );", + + "float dotProduct = dot( transformedNormal, lVector );", + "vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );", + + "#ifdef DOUBLE_SIDED", + + "vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", + + "#ifdef WRAP_AROUND", + + "vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", + + "#endif", + + "#endif", + + "#ifdef WRAP_AROUND", + + "vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", + "spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );", + + "#ifdef DOUBLE_SIDED", + + "spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );", + + "#endif", + + "#endif", + + "vLightFront += spotLightColor[ i ] * spotLightWeighting * distanceAttenuation * spotEffect;", + + "#ifdef DOUBLE_SIDED", + + "vLightBack += spotLightColor[ i ] * spotLightWeightingBack * distanceAttenuation * spotEffect;", + + "#endif", + + "}", + + "}", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", + "vec3 lVector = normalize( lDirection.xyz );", + + "float dotProduct = dot( transformedNormal, lVector );", + + "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", + "float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;", + + "vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + + "#ifdef DOUBLE_SIDED", + + "vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );", + + "#endif", + + "}", + + "#endif", + + "vLightFront = ( vLightFront + ambientLightColor + ambient) * diffuse + emissive;", + + "#ifdef DOUBLE_SIDED", + + "vLightBack = ( vLightFront + ambientLightColor + ambient) * diffuse + emissive;", + + "#endif" + + ].join("\n"), + + // LIGHTS PHYSICAL + + lights_physical_pars_vertex: [ + + "#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", + + "varying vec3 vWorldPosition;", + + "#endif" + + ].join("\n"), + + + lights_physical_vertex: [ + + "#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", + + "vWorldPosition = worldPosition.xyz;", + + "#endif", + + "#ifdef USE_SKINNING", + + "vNormal = normalize( normalMatrix * skinnedNormal.xyz );", + + "vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );", + "vTangent = normalize( normalMatrix * skinnedTangent.xyz );", + + "#else", + + "vNormal = normalize( normalMatrix * normal );", + "vTangent = normalize( normalMatrix * tangent.xyz );", + + "#endif", + + "vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );", + + + ].join("\n"), + + lights_physical_pars_fragment: [ + + "uniform vec3 ambientLightColor;", + + "#if MAX_DIR_LIGHTS > 0", + + "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", + "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", + "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDecayExponent[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#if MAX_AREA_LIGHTS > 0", + + "uniform vec3 areaLightColor[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightPosition[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightWidth[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightHeight[ MAX_AREA_LIGHTS ];", + "uniform float areaLightDistance[ MAX_AREA_LIGHTS ];", + "uniform float areaLightDecayExponent[ MAX_AREA_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP )", + + "varying vec3 vWorldPosition;", + + "#endif", + + "#ifdef WRAP_AROUND", + + "uniform vec3 wrapRGB;", + + "#endif", + + "varying vec3 vViewPosition;", + "varying vec3 vTangent;", + "varying vec3 vBinormal;", + "varying vec3 vNormal;", + + // classic Fresnel Schlick + /*"float Fresnel_Schlick( float hDotV ) {", + "float F0 = 0.04;", + "return F0 + ( 1.0 - F0 ) * pow( 1.0 - hDotV, 5.0 );", + "}",*/ + + // Calcuate the Fresnel term using the Schlick approximation (using Unreal's blend to white method) VALIDATED + "vec3 Fresnel_Schlick_SpecularBlendToWhite(vec3 specularColor, float hDotV) {", + "float Fc = pow(max( 1.0 - hDotV, 0.0 ), 5.0);", + "return saturate( 50.0 * average( specularColor ) ) * Fc + (1.0 - Fc) * specularColor;", + "}", + + "vec3 Fresnel_Schlick_SpecularBlendToWhiteRoughness(vec3 specularColor, float hDotV, float roughness) {", + "float Fc = pow(max( 1.0 - hDotV, 0.0 ), 5.0) / ( 1.0 + 3.0 * roughness );", + + "return mix( specularColor, vec3( saturate( 50.0 * average( specularColor ) ) ), Fc );", + "}", + + // Calculate the distribution term VALIDATED + "float Distribution_GGX( float roughness2, float nDotH ) {", + "float denom = nDotH * nDotH * (roughness2 - 1.0) + 1.0;", + "return roughness2 / ( PI * square( denom ) + 0.0000001 );", + "}", + + // Calculated the anisotropic GGZ distrubtion term VALIDATED + "float Distribution_GGXAniso( vec2 anisotropicM, vec2 xyDotH, float nDotH ) {", + "float anisoTerm = ( xyDotH.x * xyDotH.x / ( anisotropicM.x * anisotropicM.x ) + xyDotH.y * xyDotH.y / ( anisotropicM.y * anisotropicM.y ) + nDotH * nDotH );", + "return 1.0 / ( PI * anisotropicM.x * anisotropicM.y * anisoTerm * anisoTerm + 0.0000001 );", + "}", + + // useful for clear coat surfaces, use with Distribution_GGX. + "float Visibility_Kelemen( float vDotH ) {", + "return 1.0 / ( 4.0 * vDotH * vDotH + 0.0000001 );", + "}", + + "float Visibility_Schlick( float roughness2, float nDotL, float nDotV) {", + "float termL = (nDotL + sqrt(roughness2 + (1.0 - roughness2) * nDotL * nDotL));", + "float termV = (nDotV + sqrt(roughness2 + (1.0 - roughness2) * nDotV * nDotV));", + "return 1.0 / ( abs( termL * termV ) + 0.0000001 );", + "}", + + "float Diffuse_Lambert() {", + "return 1.0 / PI;", + "}", + + "float Diffuse_OrenNayer( float m2, float nDotV, float nDotL, float vDotH ) {", + "float termA = 1.0 - 0.5 * m2 / (m2 + 0.33);", + "float Cosri = 2.0 * vDotH - 1.0 - nDotV * nDotL;", + "float termB = 0.45 * m2 / (m2 + 0.09) * Cosri * ( Cosri >= 0.0 ? min( 1.0, nDotL / nDotV ) : nDotL );", + "return 1.0 / PI * ( nDotL * termA + termB );", + "}", + + // Helper for anisotropy rotation + "mat2 createRotationMat2( float rads) {", + "float cos_rads = cos( rads );", + "float sin_rads = sin( rads );", + "return mat2( vec2( cos_rads, sin_rads ), vec2( -sin_rads, cos_rads ) );", + "}", + + // Helper for anisotropy rotation + "vec2 calcAnisotropyUV( float anisotropyLocal) {", + "float oneMinusAbsAnisotropy = 1.0 - min( abs( anisotropyLocal ) * 0.9, 0.9 );", + "vec2 anisotropyUV = vec2 ( 1.0 / oneMinusAbsAnisotropy, oneMinusAbsAnisotropy );", + "if( anisotropy < 0.0 ) {", + "anisotropyUV.xy = anisotropyUV.yx;", // swizzel + "}", + "return anisotropyUV;", + "}" + + //"float horizonOcclusion( vec3 reflectionVector, vec3 originalNormal ) {", + // "return quare( saturate( 1.0 + uHorizonOcclude*dot( dir, vertexNormal ) ) );", + //"}" + + + ].join("\n"), + + lights_physical_fragment: [ + + "mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normal );", + + "#ifdef USE_NORMALMAP", + + "normal = perturbNormal2Arb( -vViewPosition, normal );", + + /*"vec3 normalTex = texture2D( normalMap, vNormalUv ).xyz * 2.0 - 1.0;", + "normalTex.xy *= normalScale;", + "normalTex = perturbNormal2Arb( -viewDirection, normal );", + + "normal = tsb * normalTex;",*/ + + //"vec3 originalNormal = normal;", + "#endif", + + "#if defined( USE_BUMPMAP )", + + "normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );", + + "#endif", + + "#ifdef DOUBLE_SIDED", + + "normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + + "#endif", + + "#ifdef FALLOFF", + + "vec3 modulatedFalloffColor = falloffColor;", + + "#ifdef USE_FALLOFFMAP", + + "vec4 falloffTexelColor = texelDecode( texture2D( falloffMap, vUvLocal ), ENCODING_sRGB );", + + "modulatedFalloffColor = modulatedFalloffColor * falloffTexelColor.xyz;", + + "#endif", + + "float fm = abs( dot( normal, viewDirection ) );", + + // this is a hack, it needs to be fixed. + "fm = /*falloffBlendParams.x * fm + falloffBlendParams.y * */ ( fm * fm * ( 3.0 - 2.0 * fm ) );", + + "diffuseColor = mix( modulatedFalloffColor, diffuseColor, fm );", + + "#endif", + + "float nDotV = saturate( dot( normal, viewDirection ) );", + "float m2 = pow( clamp( roughnessStrength, 0.02, 1.0 ), 4.0 );", + // specular is scaled by 0.08 per Disney PBR recommendations. + "float m2ClearCoat = pow( clamp( clearCoatRoughness, 0.02, 1.0 ), 4.0 );", + + "specularColor = mix( specularColor * SPECULAR_COEFF, diffuseColor, metallicStrength );", + "diffuseColor *= ( 1.0 - metallicStrength );", + + "#ifdef ANISOTROPY", + + "vec2 anisotropicM = calcAnisotropyUV( anisotropyStrength ) * sqrt( m2 );", + + "#ifdef ANISOTROPYROTATION", + "mat2 anisotropicRotationMatrix = createRotationMat2( anisotropyRotationStrength * 2.0 * PI );", + "#endif", + + "vec3 anisotropicS = tsb[1];", // binormal in eye space. + "vec3 anisotropicT = tsb[0];", // tangent in eye space. + + "#endif", + + "vec3 totalLighting = vec3( 0.0 );", + + "#if ( defined( USE_ENVMAP ) || defined( USE_DIFFUSEENVMAP ) ) && defined( PHYSICAL )", + + "{", + + "vec3 worldNormal = vec3( normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz ) );", + "vec3 worldView = -vec3( normalize( ( vec4( viewDirection, 0.0 ) * viewMatrix ).xyz ) );", + + "vec3 reflectVec = reflect( worldView, worldNormal );", + + "vec3 hVector = normal;//normalize( viewDirection.xyz + lVector.xyz );", + "float nDotH = saturate( dot( normal, normal ) );", + "float hDotV = saturate( dot( normal, viewDirection ) );", + "float nDotL = hDotV;//saturate( dot( normal, lVector ) );", + + + "vec3 queryVector = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );", + + "#ifdef DOUBLE_SIDED", + + "queryVector *= ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + + "#endif", + + "vec3 worldEnvNormal = vec3( normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz ) );", + "worldEnvNormal = vec3( flipEnvMap * worldEnvNormal.x, worldEnvNormal.yz );", + + "#ifdef DOUBLE_SIDED", + + "worldEnvNormal *= ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + + "#endif", + + // calculate diffuse map contribution + + "vec4 diffuseEnvColor = vec4( 0.0, 0.0, 0.0, 1.0 );", + + "#if defined( USE_DIFFUSEENVMAP )", + + "diffuseEnvColor = texelDecode( textureCube( diffuseEnvMap, worldEnvNormal ), diffuseEnvEncoding );", + + "#elif defined( USE_ENVMAP )", + + "#if defined( TEXTURE_CUBE_LOD_EXT )", + + "diffuseEnvColor = texelDecode( textureCubeLodEXT( envMap, worldEnvNormal, 9.5 ), envEncoding );", + + "#else", + + "diffuseEnvColor = texelDecode( textureCube( envMap, worldEnvNormal, 10.0 ), envEncoding );", + + "#endif", + + "#endif", + + // calculate specular map contribution + + "vec4 specularEnvColor = vec4( 0.0, 0.0, 0.0, 1.0 );", + + "#if defined( USE_ENVMAP )", + + "#if defined( TEXTURE_CUBE_LOD_EXT )", + + "float specularMIPLevel = 9.7925 - 0.5 * log2( 2.0 / ( roughness * roughness + 0.00001 ) - 1.0 );", + "specularEnvColor = texelDecode( textureCubeLodEXT( envMap, queryVector, specularMIPLevel ), envEncoding );", + + "#else", + + "specularEnvColor = mix( texelDecode( textureCube( envMap, queryVector ), envEncoding ), texelDecode( textureCube( envMap, queryVector, 10.0 ), envEncoding ), roughnessStrength );", + + "#endif", + + "#endif", + + "vec3 specClearCoat = vec3(0, 0, 0);", + + "#if defined( CLEARCOAT ) && defined( USE_ENVMAP )", + + "#if defined( TEXTURE_CUBE_LOD_EXT )", + + "float clearCoatMIPLevel = 9.7925 - 0.5 * log2( 2.0 / ( clearCoatRoughness * clearCoatRoughness + 0.00001 ) - 1.0 );", + "vec4 specularClearCoatEnvColor = texelDecode( textureCubeLodEXT( envMap, queryVector, clearCoatMIPLevel ), envEncoding );", + + "#else", + + "vec4 specularClearCoatEnvColor = mix( texelDecode( textureCube( envMap, queryVector ), envEncoding ), texelDecode( textureCube( envMap, queryVector, 10.0 ), envEncoding ), clearCoatRoughness );", + + "#endif", + + "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhiteRoughness( vec3( SPECULAR_COEFF ), nDotL, m2ClearCoat );", + "specClearCoat = specularClearCoatEnvColor.rgb * fresnelClearCoat;", + + "#endif", + + "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhiteRoughness( specularColor, nDotL, m2 );", + + // Put it all together + "vec3 spec = fresnelColor * specularEnvColor.rgb;", + "vec3 diff = diffuseColor * diffuseEnvColor.rgb;", // no Diffuse_Lambert() term, it is baked into irradiance. + + "vec3 shadingResult = spec + diff;", + + "#ifdef CLEARCOAT", + + "shadingResult = mix( shadingResult, specClearCoat, clearCoat );", + + "#endif", + // diffuse + "totalLighting += shadingResult;", + + "}", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + "float distanceAttenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );", + + "vec3 incidentLight = pointLightColor[ i ] * distanceAttenuation;", + + "lVector = normalize( lVector );", + + // diffuse + + "vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );", + "float nDotH = saturate( dot( normal, hVector ) );", + "float nDotL = saturate( dot( normal, lVector ) );", + "float hDotV = saturate( dot( hVector, viewDirection ) );", + + "#ifdef CLEARCOAT", + + "float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );", + "float visClearCoat = Visibility_Kelemen( hDotV );", + "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );", + "vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;", + + "#endif", + + "#ifdef ANISOTROPY", + + "vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );", + + "#ifdef ANISOTROPYROTATION", + "xyDotH = anisotropicRotationMatrix * xyDotH;", + "#endif", + + "float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );", + + "#else", + + "float d = Distribution_GGX( m2, nDotH );", + + "#endif", + + "float vis = Visibility_Schlick(m2, nDotL, nDotV);", + "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );", + + // Put it all together + "vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;", + "vec3 diff = nDotL * Diffuse_Lambert() * diffuseColor;", + + "#ifdef TRANSLUCENCY", + + "diff *= whiteCompliment( translucencyColor.xyz );", + + "#endif", + + "vec3 shadingResult = spec + diff;", + + "#ifdef CLEARCOAT", + + "shadingResult = mix( shadingResult, specClearCoat, clearCoat );", + + "#endif", + // diffuse + "totalLighting += incidentLight * shadingResult;", + + "#ifdef TRANSLUCENCY", + + "float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );", + + "float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );", + + "totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;", + + "#endif", + + "}", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + "float distanceAttenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );", + + "vec3 incidentLight = spotLightColor[ i ] * distanceAttenuation;", + + "lVector = normalize( lVector );", + + "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", + + "if ( spotEffect > spotLightAngleCos[ i ] ) {", + + "spotEffect = pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] );", + + // diffuse + + "incidentLight *= spotEffect;", + + "vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );", + "float nDotH = saturate( dot( normal, hVector ) );", + "float nDotL = saturate( dot( normal, lVector ) );", + "float hDotV = saturate( dot( hVector, viewDirection ) );", + + "#ifdef CLEARCOAT", + + "float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );", + "float visClearCoat = Visibility_Kelemen( hDotV );", + "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );", + "vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;", + + "#endif", + + "#ifdef ANISOTROPY", + + "vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );", + + "#ifdef ANISOTROPYROTATION", + "xyDotH = anisotropicRotationMatrix * xyDotH;", + "#endif", + + "float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );", + + "#else", + + "float d = Distribution_GGX( m2, nDotH );", + + "#endif", + + "float vis = Visibility_Schlick(m2, nDotL, nDotV);", + "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );", + + // Put it all together + "vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;", + "vec3 diff = nDotL * Diffuse_Lambert() * diffuseColor;", + + "#ifdef TRANSLUCENCY", + + "diff *= whiteCompliment( translucencyColor.xyz );", + + "#endif", + + "vec3 shadingResult = spec + diff;", + + "#ifdef CLEARCOAT", + + "shadingResult = mix( shadingResult, specClearCoat, clearCoat );", + + "#endif", + // diffuse + "totalLighting += incidentLight * shadingResult;", + + "#ifdef TRANSLUCENCY", + + "float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );", + + "float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );", + + "totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;", + + "#endif", + + "}", + + "}", + + "#endif", + + "#if MAX_DIR_LIGHTS > 0", + + "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", + "vec3 lVector = normalize( lDirection.xyz );", + + "vec3 incidentLight = directionalLightColor[ i ];", + + "vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );", + "float nDotH = saturate( dot( normal, hVector ) );", + "float nDotL = saturate( dot( normal, lVector ) );", + "float hDotV = saturate( dot( hVector, viewDirection ) );", + + "#ifdef CLEARCOAT", + + "float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );", + "float visClearCoat = Visibility_Kelemen( hDotV );", + "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );", + "vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;", + + "#endif", + + "#ifdef ANISOTROPY", + + "vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );", + + "#ifdef ANISOTROPYROTATION", + "xyDotH = anisotropicRotationMatrix * xyDotH;", + "#endif", + + "float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );", + + "#else", + + "float d = Distribution_GGX( m2, nDotH );", + + "#endif", + + "float vis = Visibility_Schlick(m2, nDotL, nDotV);", + "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );", + + // Put it all together + "vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;", + "vec3 diff = nDotL * Diffuse_Lambert() * diffuseColor;", + + "#ifdef TRANSLUCENCY", + + "diff *= whiteCompliment( translucencyColor.xyz );", + + "#endif", + + "vec3 shadingResult = spec + diff;", + + "#ifdef CLEARCOAT", + + "shadingResult = mix( shadingResult, specClearCoat, clearCoat );", + + "#endif", + // diffuse + "totalLighting += incidentLight * shadingResult;", + + "#ifdef TRANSLUCENCY", + + "float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );", + + "float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );", + + "totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;", + + "#endif", + + "}", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", + "vec3 lVector = normalize( lDirection.xyz );", + + // diffuse + + "float nDotL = dot( normal, lVector );", + + // based on page 325 of Real-Time Rendering., equation (8.43) + "vec3 hemiColor = ( PI / 2.0 ) * ( ( 1.0 + nDotL ) * hemisphereLightSkyColor[ i ] + ( 1.0 - nDotL ) * hemisphereLightGroundColor[ i ] );", + + "totalLighting += diffuseColor * hemiColor;", + + "}", + + "#endif", + + "#if MAX_AREA_LIGHTS > 0", + + "for( int i = 0; i < MAX_AREA_LIGHTS; i ++ ) {", + + "vec3 lPosition = ( viewMatrix * vec4( areaLightPosition[ i ], 1.0 ) ).xyz;", + //"vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + "vec3 width = areaLightWidth[ i ];", + "vec3 height = areaLightHeight[ i ];", + "vec3 up = normalize( ( viewMatrix * vec4( height, 0.0 ) ).xyz );", + "vec3 right = normalize( ( viewMatrix * vec4( width, 0.0 ) ).xyz );", + "vec3 pnormal = normalize( cross( right, up ) );", + + "float widthScalar = length( width );", + "float heightScalar = length( height );", + + //project onto plane and calculate direction from center to the projection. + "vec3 projection = projectOnPlane( -vViewPosition.xyz, lPosition, pnormal );", // projection in plane + "vec3 dir = projection - lPosition;", + + //calculate distance from area: + "vec2 diagonal = vec2( dot( dir, right ), dot( dir, up ) );", + "vec2 nearest2D = vec2( clamp( diagonal.x, -widthScalar, widthScalar ), clamp( diagonal.y, -heightScalar, heightScalar ) );", + "vec3 nearestPointInside = lPosition + ( right *nearest2D.x + up * nearest2D.y );", + + "vec3 lVector = ( nearestPointInside + vViewPosition.xyz );", + "float distanceAttenuation = calcLightAttenuation( length( lVector ), areaLightDistance[ i ], areaLightDecayExponent[i] );", + "lVector = normalize( lVector );", + + "vec3 incidentLight = areaLightColor[ i ] * distanceAttenuation * 0.01;", // the 0.01 is the area light intensity scaling. + + "float nDotLDiffuse = saturate( dot( normal, lVector ) );", + + "vec3 diff = Diffuse_Lambert() * diffuseColor * widthScalar * heightScalar;", + + "vec3 viewReflection = reflect( viewDirection.xyz, normal );", + "vec3 reflectionLightPlaneIntersection = linePlaneIntersect( -vViewPosition.xyz, viewReflection, lPosition, pnormal );", + + "float specAngle = dot( viewReflection, pnormal );", + + // && dot( -vViewPosition.xyz - areaLightPosition[ i ], -pnormal ) >= 0.0 + "if ( specAngle < 0.0 ) {", + + "vec3 dirSpec = reflectionLightPlaneIntersection - lPosition;", + "vec2 dirSpec2D = vec2( dot( dirSpec, right ), dot( dirSpec, up ) );", + "vec2 nearestSpec2D = vec2( clamp( dirSpec2D.x, -widthScalar, widthScalar ), clamp( dirSpec2D.y, -heightScalar, heightScalar ) );", + "lVector = normalize( lPosition + ( right *nearestSpec2D.x + up * nearestSpec2D.y ) + vViewPosition.xyz );", + + "} else { ", + + "lVector = vec3( 0 );", + + "}", + + "vec3 hVector = normalize( viewDirection.xyz + lVector.xyz );", + "float nDotH = saturate( dot( normal, hVector ) );", + "float nDotL = saturate( dot( normal, lVector ) );", + "float hDotV = saturate( dot( hVector, viewDirection ) );", + + "#ifdef CLEARCOAT", + + "float dClearCoat = Distribution_GGX( m2ClearCoat, nDotH );", + "float visClearCoat = Visibility_Kelemen( hDotV );", + "vec3 fresnelClearCoat = Fresnel_Schlick_SpecularBlendToWhite( vec3( SPECULAR_COEFF ), hDotV );", + "vec3 specClearCoat = clamp( nDotL * dClearCoat * visClearCoat, 0.0, 10.0 ) * fresnelClearCoat;", + + "#endif", + + "#ifdef TRANSLUCENCY", + + "diff *= whiteCompliment( translucencyColor.xyz );", + + "#endif", + + "#ifdef CLEARCOAT", + + "diff = mix( diff, specClearCoat, clearCoat );", + + "#endif", + + + "#ifdef ANISOTROPY", + + "vec2 xyDotH = vec2( dot( anisotropicS, hVector ), dot( anisotropicT, hVector ) );", + + "#ifdef ANISOTROPYROTATION", + "xyDotH = anisotropicRotationMatrix * xyDotH;", + "#endif", + + "float d = Distribution_GGXAniso( anisotropicM, xyDotH, nDotH );", + + "#else", + + "float d = Distribution_GGX( m2, nDotH );", + + "#endif", + + "float vis = Visibility_Schlick(m2, nDotL, nDotV);", + "vec3 fresnelColor = Fresnel_Schlick_SpecularBlendToWhite( specularColor, hDotV );", + + // Put it all together + "vec3 spec = clamp( nDotL * d * vis, 0.0, 10.0 ) * fresnelColor;", + + "totalLighting += incidentLight * spec;", + "totalLighting += incidentLight * nDotLDiffuse * diff;", + + "#ifdef TRANSLUCENCY", + + "float lightNormalTL = mix( 1.0, pow( abs( dot( lVector.xyz, normal ) ), translucencyNormalPower ), translucencyNormalAlpha );", + + "float viewNormalTL = mix( 1.0, pow( abs( dot( viewDirection.xyz, lVector.xyz) ), translucencyViewPower ), translucencyViewAlpha );", + + "totalLighting += lightNormalTL * viewNormalTL * translucencyColor.rgb * incidentLight;", + + "#endif", + + "}", + + "#endif", + + "#ifdef CLEARCOAT", + + "totalLighting += diffuseColor * ( ambientLightColor * ( 1.0 - clearCoat ) );", + + "#else", + + "totalLighting += diffuseColor * ambientLightColor;", + + "#endif", + + "gl_FragColor.xyz += totalLighting;", + + "vec3 emissiveLocal = emissive;", + + "#ifdef USE_EMISSIVEMAP", + + "vec3 emissiveColor = texture2D( emissiveMap, vUv2 ).xyz;", + + "#ifdef GAMMA_INPUT", + + "emissiveColor *= emissiveColor;", + + "#endif", + + "emissiveLocal *= emissiveColor;", + + "#endif", + + "gl_FragColor.xyz += emissiveLocal;", + + "vec3 ambientLocal = ambient;", + + "#ifdef USE_LIGHTMAP", + + "vec3 ambientColor = texture2D( lightMap, vUv2 ).xyz;", + + "#ifdef GAMMA_INPUT", + + "ambientColor *= ambientColor;", + + "#endif", + + "ambientLocal *= ambientColor;", + + "#ifdef CLEARCOAT", + + "ambientLocal *= ( 1.0 - clearCoat );", + + "#endif", + + "#endif", + + "gl_FragColor.xyz += diffuseColor * ambientLocal;", + + ].join("\n"), + + // LIGHTS PHONG + + lights_phong_pars_vertex: [ + + "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", + + "varying vec3 vWorldPosition;", + + "#endif" + + ].join("\n"), + + + lights_phong_vertex: [ + + "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )", + + "vWorldPosition = worldPosition.xyz;", + + "#endif" + + ].join("\n"), + + lights_phong_pars_fragment: [ + + "uniform vec3 ambientLightColor;", + + "#if MAX_DIR_LIGHTS > 0", + + "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", + "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", + "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDecayExponent[ MAX_POINT_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDecayExponent[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#if MAX_AREA_LIGHTS > 0", + + "uniform vec3 areaLightColor[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightPosition[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightWidth[ MAX_AREA_LIGHTS ];", + "uniform vec3 areaLightHeight[ MAX_AREA_LIGHTS ];", + "uniform float areaLightDistance[ MAX_AREA_LIGHTS ];", + "uniform float areaLightDecayExponent[ MAX_AREA_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0 || MAX_AREA_LIGHTS > 0 || defined( USE_BUMPMAP )", + + "varying vec3 vWorldPosition;", + + "#endif", + + "#ifdef WRAP_AROUND", + + "uniform vec3 wrapRGB;", + + "#endif", + + "varying vec3 vViewPosition;", + "varying vec3 vNormal;" + + ].join("\n"), + + lights_phong_fragment: [ + + "vec3 normal = normalize( vNormal );", + "vec3 viewDirection = normalize( vViewPosition );", + + "#ifdef DOUBLE_SIDED", + + "normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );", + + "#endif", + + "#ifdef USE_NORMALMAP", + + "normal = perturbNormal2Arb( -vViewPosition, normal );", + + "#elif defined( USE_BUMPMAP )", + + "normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "vec3 pointDiffuse = vec3( 0.0 );", + "vec3 pointSpecular = vec3( 0.0 );", + + "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + "float distanceAttenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecayExponent[i] );", + + "lVector = normalize( lVector );", + + // diffuse + + "float dotProduct = dot( normal, lVector );", + + "float pointDiffuseWeight = max( dotProduct, 0.0 );", + + "pointDiffuse += pointLightColor[ i ] * pointDiffuseWeight * distanceAttenuation;", + + // specular + + "vec3 pointHalfVector = normalize( lVector + viewDirection );", + "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", + "float pointSpecularWeight = specularStrength * pow( max( pointDotNormalHalf, 0.0 ), shininess );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );", + "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * distanceAttenuation * specularNormalization;", + + "}", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "vec3 spotDiffuse = vec3( 0.0 );", + "vec3 spotSpecular = vec3( 0.0 );", + + "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", + "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + "float distanceAttenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecayExponent[i] );", + + "lVector = normalize( lVector );", + + "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", + + "if ( spotEffect > spotLightAngleCos[ i ] ) {", + + "spotEffect = pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] );", + + // diffuse + + "float dotProduct = dot( normal, lVector );", + + "#ifdef WRAP_AROUND", + + "float spotDiffuseWeightFull = max( dotProduct, 0.0 );", + "float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", + + "vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", + + "#else", + + "float spotDiffuseWeight = max( dotProduct, 0.0 );", + + "#endif", + + "spotDiffuse += spotLightColor[ i ] * spotDiffuseWeight * distanceAttenuation * spotEffect;", + + // specular + + "vec3 spotHalfVector = normalize( lVector + viewDirection );", + "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", + "float spotSpecularWeight = specularStrength * pow( max( spotDotNormalHalf, 0.0 ), shininess );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );", + "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * distanceAttenuation * specularNormalization * spotEffect;", + + "}", + + "}", + + "#endif", + + "#if MAX_DIR_LIGHTS > 0", + + "vec3 dirDiffuse = vec3( 0.0 );", + "vec3 dirSpecular = vec3( 0.0 );" , + + "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", + "vec3 dirVector = normalize( lDirection.xyz );", + + // diffuse + + "float dotProduct = dot( normal, dirVector );", + + "#ifdef WRAP_AROUND", + + "float dirDiffuseWeightFull = max( dotProduct, 0.0 );", + "float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", + + "vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );", + + "#else", + + "float dirDiffuseWeight = max( dotProduct, 0.0 );", + + "#endif", + + "dirDiffuse += directionalLightColor[ i ] * dirDiffuseWeight;", + + // specular + + "vec3 dirHalfVector = normalize( dirVector + viewDirection );", + "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", + "float dirSpecularWeight = specularStrength * pow( max( dirDotNormalHalf, 0.0 ), shininess );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + //"dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;", + + "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );", + "dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", + + + "}", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "vec3 hemiDiffuse = vec3( 0.0 );", + "vec3 hemiSpecular = vec3( 0.0 );" , + + "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", + "vec3 lVector = normalize( lDirection.xyz );", + + // diffuse + + "float dotProduct = dot( normal, lVector );", + "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", + + "vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + + "hemiDiffuse += hemiColor;", + + // specular (sky light) + + "vec3 hemiHalfVectorSky = normalize( lVector + viewDirection );", + "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", + "float hemiSpecularWeightSky = specularStrength * pow( max( hemiDotNormalHalfSky, 0.0 ), shininess );", + + // specular (ground light) + + "vec3 lVectorGround = -lVector;", + + "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewDirection );", + "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", + "float hemiSpecularWeightGround = specularStrength * pow( max( hemiDotNormalHalfGround, 0.0 ), shininess );", + + "float dotProductGround = dot( normal, lVectorGround );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + "vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );", + "vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );", + "hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", + + "}", + + "#endif", + + "#if MAX_AREA_LIGHTS > 0", + + "vec3 areaDiffuse = vec3( 0.0 );", + "vec3 areaSpecular = vec3( 0.0 );", + + "for( int i = 0; i < MAX_AREA_LIGHTS; i ++ ) {", + + "vec3 lPosition = ( viewMatrix * vec4( areaLightPosition[ i ], 1.0 ) ).xyz;", + //"vec3 lVector = lPosition.xyz + vViewPosition.xyz;", + + "vec3 width = areaLightWidth[ i ];", + "vec3 height = areaLightHeight[ i ];", + "vec3 up = normalize( ( viewMatrix * vec4( height, 0.0 ) ).xyz );", + "vec3 right = normalize( ( viewMatrix * vec4( width, 0.0 ) ).xyz );", + "vec3 pnormal = normalize( cross( right, up ) );", + + "float widthScalar = length( width );", + "float heightScalar = length( height );", + + //project onto plane and calculate direction from center to the projection. + "vec3 projection = projectOnPlane( -vViewPosition.xyz, lPosition, pnormal );", // projection in plane + "vec3 dir = projection - lPosition;", + + //calculate distance from area: + "vec2 diagonal = vec2( dot( dir, right ), dot( dir, up ) );", + "vec2 nearest2D = vec2( clamp( diagonal.x, -widthScalar, widthScalar ), clamp( diagonal.y, -heightScalar, heightScalar ) );", + "vec3 nearestPointInside = lPosition + ( right *nearest2D.x + up * nearest2D.y );", + + "vec3 lVector = ( nearestPointInside + vViewPosition.xyz );", + "float distanceAttenuation = calcLightAttenuation( length( lVector ), areaLightDistance[ i ], areaLightDecayExponent[i] );", + "lVector = normalize( lVector );", + + "float nDotLDiffuse = saturate( dot( normal, lVector ) );", + + "vec3 viewReflection = reflect( viewDirection.xyz, normal );", + "vec3 reflectionLightPlaneIntersection = linePlaneIntersect( -vViewPosition.xyz, viewReflection, lPosition, pnormal );", + + "float specAngle = dot( viewReflection, pnormal );", + + "if ( specAngle < 0.0 ) {", + + "vec3 dirSpec = reflectionLightPlaneIntersection - lPosition;", + "vec2 dirSpec2D = vec2( dot( dirSpec, right ), dot( dirSpec, up ) );", + "vec2 nearestSpec2D = vec2( clamp( dirSpec2D.x, -widthScalar, widthScalar ), clamp( dirSpec2D.y, -heightScalar, heightScalar ) );", + "lVector = normalize( lPosition + ( right *nearestSpec2D.x + up * nearestSpec2D.y ) + vViewPosition.xyz );", + + "} else { ", + + "lVector = vec3( 0 );", + + "}", + + // diffuse + + "float dotProduct = nDotLDiffuse;", + + "float areaDiffuseWeight = max( dotProduct, 0.0 );", + + "areaDiffuse += areaLightColor[ i ] * areaDiffuseWeight * distanceAttenuation * widthScalar * heightScalar * 0.01;", // the 0.01 is the area light intensity scaling. + + // specular + + "vec3 areaHalfVector = normalize( lVector + viewDirection );", + "float areaDotNormalHalf = max( dot( normal, areaHalfVector ), 0.0 );", + "float areaSpecularWeight = specularStrength * pow( max( areaDotNormalHalf, 0.0 ), shininess );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, areaHalfVector ), 0.0 ), 5.0 );", + "areaSpecular += schlick * areaLightColor[ i ] * areaSpecularWeight * areaDiffuseWeight * distanceAttenuation * specularNormalization * 0.01;", // the 0.01 is the area light intensity scaling. + + "}", + + "#endif", + + "vec3 totalDiffuse = vec3( 0.0 );", + "vec3 totalSpecular = vec3( 0.0 );", + + "#if MAX_DIR_LIGHTS > 0", + + "totalDiffuse += dirDiffuse;", + "totalSpecular += dirSpecular;", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "totalDiffuse += hemiDiffuse;", + "totalSpecular += hemiSpecular;", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "totalDiffuse += pointDiffuse;", + "totalSpecular += pointSpecular;", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "totalDiffuse += spotDiffuse;", + "totalSpecular += spotSpecular;", + + "#endif", + + "#if MAX_AREA_LIGHTS > 0", + + "totalDiffuse += areaDiffuse;", + "totalSpecular += areaSpecular;", + + "#endif", + "vec3 ambientLocal = ambient;", + + "#ifdef USE_LIGHTMAP", + + "vec3 ambientColor = texture2D( lightMap, vUv2 ).xyz;", + + "#ifdef GAMMA_INPUT", + + "ambientColor *= ambientColor;", + + "#endif", + + "ambientLocal *= ambientColor;", + + "#endif", + + "gl_FragColor.xyz = diffuseColor * ( totalDiffuse + ambientLightColor + ambientLocal ) + totalSpecular;", + + "vec3 emissiveLocal = emissive;", + + "#ifdef USE_EMISSIVEMAP", + + "vec3 emissiveColor = texture2D( emissiveMap, vUv2 ).xyz;", + + "#ifdef GAMMA_INPUT", + + "emissiveColor *= emissiveColor;", + + "#endif", + + "emissiveLocal *= emissiveColor;", + + "#endif", + + "gl_FragColor.xyz += emissiveLocal.xyz;", + + ].join("\n"), + + // VERTEX COLORS + + color_pars_fragment: [ + + "#ifdef USE_COLOR", + + "varying vec3 vColor;", + + "#endif" + + ].join("\n"), + + + color_fragment: [ + + "#ifdef USE_COLOR", + + "gl_FragColor = gl_FragColor * vec4( vColor, 1.0 );", + + "#endif" + + ].join("\n"), + + color_pars_vertex: [ + + "#ifdef USE_COLOR", + + "varying vec3 vColor;", + + "#endif" + + ].join("\n"), + + + color_vertex: [ + + "#ifdef USE_COLOR", + + "#ifdef GAMMA_INPUT", + + "vColor = color * color;", + + "#else", + + "vColor = color;", + + "#endif", + + "#endif" + + ].join("\n"), + + // SKINNING + + skinning_pars_vertex: [ + + "#ifdef USE_SKINNING", + + "#ifdef BONE_TEXTURE", + + "uniform sampler2D boneTexture;", + "uniform int boneTextureWidth;", + "uniform int boneTextureHeight;", + + "mat4 getBoneMatrix( const float i ) {", + + "float j = i * 4.0;", + "float x = mod( j, float( boneTextureWidth ) );", + "float y = floor( j / float( boneTextureWidth ) );", + + "float dx = 1.0 / float( boneTextureWidth );", + "float dy = 1.0 / float( boneTextureHeight );", + + "y = dy * ( y + 0.5 );", + + "vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );", + "vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );", + "vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );", + "vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );", + + "mat4 bone = mat4( v1, v2, v3, v4 );", + + "return bone;", + + "}", + + "#else", + + "uniform mat4 boneGlobalMatrices[ MAX_BONES ];", + + "mat4 getBoneMatrix( const float i ) {", + + "mat4 bone = boneGlobalMatrices[ int(i) ];", + "return bone;", + + "}", + + "#endif", + + "#endif" + + ].join("\n"), + + skinbase_vertex: [ + + "#ifdef USE_SKINNING", + + "mat4 boneMatX = getBoneMatrix( skinIndex.x );", + "mat4 boneMatY = getBoneMatrix( skinIndex.y );", + "mat4 boneMatZ = getBoneMatrix( skinIndex.z );", + "mat4 boneMatW = getBoneMatrix( skinIndex.w );", + + "#endif" + + ].join("\n"), + + skinning_vertex: [ + + "#ifdef USE_SKINNING", + + "#ifdef USE_MORPHTARGETS", + + "vec4 skinVertex = vec4( morphed, 1.0 );", + + "#else", + + "vec4 skinVertex = vec4( position, 1.0 );", + + "#endif", + + "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", + "skinned += boneMatY * skinVertex * skinWeight.y;", + "skinned += boneMatZ * skinVertex * skinWeight.z;", + "skinned += boneMatW * skinVertex * skinWeight.w;", + + "#endif" + + ].join("\n"), + + // MORPHING + + morphtarget_pars_vertex: [ + + "#ifdef USE_MORPHTARGETS", + + "#ifndef USE_MORPHNORMALS", + + "uniform float morphTargetInfluences[ 8 ];", + + "#else", + + "uniform float morphTargetInfluences[ 4 ];", + + "#endif", + + "#endif" + + ].join("\n"), + + morphtarget_vertex: [ + + "#ifdef USE_MORPHTARGETS", + + "vec3 morphed = vec3( 0.0 );", + "morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];", + "morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];", + "morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];", + "morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];", + + "#ifndef USE_MORPHNORMALS", + + "morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];", + "morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];", + "morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];", + "morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];", + + "#endif", + + "morphed += position;", + + "#endif" + + ].join("\n"), + + default_vertex : [ + + "vec4 mvPosition;", + + "#ifdef USE_SKINNING", + + "mvPosition = modelViewMatrix * skinned;", + + "#endif", + + "#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )", + + "mvPosition = modelViewMatrix * vec4( morphed, 1.0 );", + + "#endif", + + "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )", + + "mvPosition = modelViewMatrix * vec4( position, 1.0 );", + + "#endif", + + "gl_Position = projectionMatrix * mvPosition;" + + ].join("\n"), + + morphnormal_vertex: [ + + "#ifdef USE_MORPHNORMALS", + + "vec3 morphedNormal = vec3( 0.0 );", + + "morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];", + "morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];", + "morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];", + "morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];", + + "morphedNormal += normal;", + + "#endif" + + ].join("\n"), + + skinnormal_vertex: [ + + "#ifdef USE_SKINNING", + + "mat4 skinMatrix = skinWeight.x * boneMatX;", + "skinMatrix += skinWeight.y * boneMatY;", + + "#ifdef USE_MORPHNORMALS", + + "vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );", + + "#else", + + "vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );", + + "#endif", + + "#endif" + + ].join("\n"), + + defaultnormal_vertex: [ + + "vec3 objectNormal;", + + "#ifdef USE_SKINNING", + + "objectNormal = skinnedNormal.xyz;", + + "#endif", + + "#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )", + + "objectNormal = morphedNormal;", + + "#endif", + + "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )", + + "objectNormal = normal;", + + "#endif", + + "#ifdef FLIP_SIDED", + + "objectNormal = -objectNormal;", + + "#endif", + + "vec3 transformedNormal = normalMatrix * objectNormal;" + + ].join("\n"), + + // SHADOW MAP + + // based on SpiderGL shadow map and Fabien Sanglard's GLSL shadow mapping examples + // http://spidergl.org/example.php?id=6 + // http://fabiensanglard.net/shadowmapping + + shadowmap_pars_fragment: [ + + "#ifdef USE_SHADOWMAP", + + "uniform sampler2D shadowMap[ MAX_SHADOWS ];", + "uniform vec2 shadowMapSize[ MAX_SHADOWS ];", + + "uniform float shadowDarkness[ MAX_SHADOWS ];", + "uniform float shadowBias[ MAX_SHADOWS ];", + + "varying vec4 vShadowCoord[ MAX_SHADOWS ];", + + "float unpackDepth( const vec4 rgba_depth ) {", + + "const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );", + "float depth = dot( rgba_depth, bit_shift );", + "return depth;", + + "}", + + "#endif" + + ].join("\n"), + + shadowmap_fragment: [ + + "#ifdef USE_SHADOWMAP", + + "#ifdef SHADOWMAP_DEBUG", + + "vec3 frustumColors[3];", + "frustumColors[0] = vec3( 1.0, 0.5, 0.0 );", + "frustumColors[1] = vec3( 0.0, 1.0, 0.8 );", + "frustumColors[2] = vec3( 0.0, 0.5, 1.0 );", + + "#endif", + + "#ifdef SHADOWMAP_CASCADE", + + "int inFrustumCount = 0;", + + "#endif", + + "float fDepth;", + "vec3 shadowColor = vec3( 1.0 );", + + "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + + "vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;", + + // "if ( something && something )" breaks ATI OpenGL shader compiler + // "if ( all( something, something ) )" using this instead + + "bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );", + "bool inFrustum = all( inFrustumVec );", + + // don't shadow pixels outside of light frustum + // use just first frustum (for cascades) + // don't shadow pixels behind far plane of light frustum + + "#ifdef SHADOWMAP_CASCADE", + + "inFrustumCount += int( inFrustum );", + "bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );", + + "#else", + + "bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );", + + "#endif", + + "bool frustumTest = all( frustumTestVec );", + + "if ( frustumTest ) {", + + "shadowCoord.z += shadowBias[ i ];", + + "#if defined( SHADOWMAP_TYPE_PCF )", + + // Percentage-close filtering + // (9 pixel kernel) + // http://fabiensanglard.net/shadowmappingPCF/ + + "float shadow = 0.0;", + + /* + // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL + // must enroll loop manually + + "for ( float y = -1.25; y <= 1.25; y += 1.25 )", + "for ( float x = -1.25; x <= 1.25; x += 1.25 ) {", + + "vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );", + + // doesn't seem to produce any noticeable visual difference compared to simple "texture2D" lookup + //"vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );", + + "float fDepth = unpackDepth( rgbaDepth );", + + "if ( fDepth < shadowCoord.z )", + "shadow += 1.0;", + + "}", + + "shadow /= 9.0;", + + */ + + "const float shadowDelta = 1.0 / 9.0;", + + "float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", + "float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", + + "float dx0 = -1.25 * xPixelOffset;", + "float dy0 = -1.25 * yPixelOffset;", + "float dx1 = 1.25 * xPixelOffset;", + "float dy1 = 1.25 * yPixelOffset;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", + "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", + + "shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", + + "#elif defined( SHADOWMAP_TYPE_PCF_SOFT )", + + // Percentage-close filtering + // (9 pixel kernel) + // http://fabiensanglard.net/shadowmappingPCF/ + + "float shadow = 0.0;", + + "float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", + "float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", + + "float dx0 = -1.0 * xPixelOffset;", + "float dy0 = -1.0 * yPixelOffset;", + "float dx1 = 1.0 * xPixelOffset;", + "float dy1 = 1.0 * yPixelOffset;", + + "mat3 shadowKernel;", + "mat3 depthKernel;", + + "depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", + "depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", + "depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );", + "depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", + "depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", + "depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", + "depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", + "depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", + "depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", + + "vec3 shadowZ = vec3( shadowCoord.z );", + "shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));", + "shadowKernel[0] *= vec3(0.25);", + + "shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));", + "shadowKernel[1] *= vec3(0.25);", + + "shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));", + "shadowKernel[2] *= vec3(0.25);", + + "vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );", + + "shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );", + "shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );", + + "vec4 shadowValues;", + "shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );", + "shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );", + "shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );", + "shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );", + + "shadow = dot( shadowValues, vec4( 1.0 ) );", + + "shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", + + "#else", + + "vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );", + "float fDepth = unpackDepth( rgbaDepth );", + + "if ( fDepth < shadowCoord.z )", + + // spot with multiple shadows is darker + + "shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );", + + // spot with multiple shadows has the same color as single shadow spot + + //"shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );", + + "#endif", + + "}", + + + "#ifdef SHADOWMAP_DEBUG", + + "#ifdef SHADOWMAP_CASCADE", + + "if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];", + + "#else", + + "if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];", + + "#endif", + + "#endif", + + "}", + + "#ifdef GAMMA_OUTPUT", + + "shadowColor *= shadowColor;", + + "#endif", + + "gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;", + + "#endif" + + ].join("\n"), + + shadowmap_pars_vertex: [ + + "#ifdef USE_SHADOWMAP", + + "varying vec4 vShadowCoord[ MAX_SHADOWS ];", + "uniform mat4 shadowMatrix[ MAX_SHADOWS ];", + + "#endif" + + ].join("\n"), + + shadowmap_vertex: [ + + "#ifdef USE_SHADOWMAP", + + "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + + "vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", + + "}", + + "#endif" + + ].join("\n"), + + // ALPHATEST + + alphatest_fragment: [ + + "#ifdef ALPHATEST", + + "if ( gl_FragColor.a < ALPHATEST ) discard;", + + "#endif" + + ].join("\n"), + + // LINEAR SPACE + + linear_to_gamma_fragment: [ + + "#ifdef GAMMA_OUTPUT", + + "gl_FragColor.xyz = sqrt( gl_FragColor.xyz );", + + "#endif" + + ].join("\n") + + +}; +/** + * Uniform Utilities + */ + +THREE.UniformsUtils = { + + merge: function ( uniforms ) { + + var u, p, tmp, merged = {}; + + for ( u = 0; u < uniforms.length; u ++ ) { + + tmp = this.clone( uniforms[ u ] ); + + for ( p in tmp ) { + + merged[ p ] = tmp[ p ]; + + } + + } + + return merged; + + }, + + clone: function ( uniforms_src ) { + + var u, p, parameter, parameter_src, uniforms_dst = {}; + + for ( u in uniforms_src ) { + + uniforms_dst[ u ] = {}; + + for ( p in uniforms_src[ u ] ) { + + parameter_src = uniforms_src[ u ][ p ]; + + if ( parameter_src instanceof THREE.Color || + parameter_src instanceof THREE.Vector2 || + parameter_src instanceof THREE.Vector3 || + parameter_src instanceof THREE.Vector4 || + parameter_src instanceof THREE.Matrix4 || + parameter_src instanceof THREE.Texture ) { + + uniforms_dst[ u ][ p ] = parameter_src.clone(); + + } else if ( parameter_src instanceof Array ) { + + uniforms_dst[ u ][ p ] = parameter_src.slice(); + + } else { + + uniforms_dst[ u ][ p ] = parameter_src; + + } + + } + + } + + return uniforms_dst; + + } + +}; +/** + * Uniforms library for shared webgl shaders + */ + +THREE.UniformsLib = { + + common: { + + "diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, + "opacity" : { type: "f", value: 1.0 }, + + "map" : { type: "t", value: null }, + "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "gainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, + + "lightMap" : { type: "t", value: null }, + "emissiveMap" : { type: "t", value: null }, + "envMap" : { type: "t", value: null }, + "envEncoding" : { type: "i", value: 0 }, + "diffuseEnvMap" : { type: "t", value: null }, + "diffuseEnvEncoding" : { type: "i", value: 0 }, + "flipEnvMap" : { type: "f", value: -1 }, + "useRefract" : { type: "i", value: 0 }, + "reflectivity" : { type: "f", value: 1.0 }, + "refractionRatio" : { type: "f", value: 0.98 }, + "combine" : { type: "i", value: 0 }, + + "morphTargetInfluences" : { type: "f", value: 0 } + + }, + + specularmap: { + + "specularMap" : { type: "t", value: null }, + "specularOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "specularGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, + + }, + + bumpmap: { + + "bumpMap" : { type: "t", value: null }, + "bumpScale" : { type: "f", value: 1 }, // used instead of 'bumpGainBrightness' + "bumpOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) } + + }, + + opacitymap: { + + "opacityMap" : { type: "t", value: null }, + "opacityOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "opacityGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, + + }, + + normalmap: { + + "normalMap" : { type: "t", value: null }, + "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }, // used instead of 'normalGainBrightness' + "normalOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) } + + }, + + fog : { + + "fogDensity" : { type: "f", value: 0.00025 }, + "fogNear" : { type: "f", value: 1 }, + "fogFar" : { type: "f", value: 2000 }, + "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } + + }, + + lights: { + + "ambientLightColor" : { type: "fv", value: [] }, + + "directionalLightDirection" : { type: "fv", value: [] }, + "directionalLightColor" : { type: "fv", value: [] }, + + "hemisphereLightDirection" : { type: "fv", value: [] }, + "hemisphereLightSkyColor" : { type: "fv", value: [] }, + "hemisphereLightGroundColor" : { type: "fv", value: [] }, + + "pointLightColor" : { type: "fv", value: [] }, + "pointLightPosition" : { type: "fv", value: [] }, + "pointLightDistance" : { type: "fv1", value: [] }, + "pointLightDecayExponent" : { type: "fv1", value: [] }, + + "spotLightColor" : { type: "fv", value: [] }, + "spotLightPosition" : { type: "fv", value: [] }, + "spotLightDirection" : { type: "fv", value: [] }, + "spotLightDistance" : { type: "fv1", value: [] }, + "spotLightDecayExponent" : { type: "fv1", value: [] }, + "spotLightAngleCos" : { type: "fv1", value: [] }, + "spotLightExponent" : { type: "fv1", value: [] }, + + "areaLightColor" : { type: "fv", value: [] }, + "areaLightPosition" : { type: "fv", value: [] }, + "areaLightDistance" : { type: "fv1", value: [] }, + "areaLightDecayExponent" : { type: "fv1", value: [] }, + "areaLightWidth" : { type: "fv", value: [] }, + "areaLightHeight" : { type: "fv", value: [] } + + }, + + particle: { + + "psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, + "opacity" : { type: "f", value: 1.0 }, + "size" : { type: "f", value: 1.0 }, + "scale" : { type: "f", value: 1.0 }, + "map" : { type: "t", value: null }, + + "fogDensity" : { type: "f", value: 0.00025 }, + "fogNear" : { type: "f", value: 1 }, + "fogFar" : { type: "f", value: 2000 }, + "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } + + }, + + shadowmap: { + + "shadowMap": { type: "tv", value: [] }, + "shadowMapSize": { type: "v2v", value: [] }, + + "shadowBias" : { type: "fv1", value: [] }, + "shadowDarkness": { type: "fv1", value: [] }, + + "shadowMatrix" : { type: "m4v", value: [] } + + } + +}; +/** + * Webgl Shader Library for three.js + * + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author mikael emtinger / http://gomo.se/ + * @author bhouston / http://clara.io/ + */ + + +THREE.ShaderLib = { + + + 'physical': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "bumpmap" ], + THREE.UniformsLib[ "normalmap" ], + //THREE.UniformsLib[ "roughnessmap" ], TODO: Implement me! + //THREE.UniformsLib[ "metallicmap" ], TODO: Implement me! + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], + THREE.UniformsLib[ "opacitymap" ], + THREE.UniformsLib[ "specularmap" ], + + { + "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "specular" : { type: "c", value: new THREE.Color( 0xFFFFFF ) }, + "falloffColor" : { type: "c", value: new THREE.Color( 0xFFFFFF ) }, + "falloffMap" : { type: "t", value: null }, + "falloffBlendParams" : { type: "v4", value: new THREE.Vector4( 1, 0, 0, 1 ) }, + + "clearCoat": { type: "f", value: 0.0 }, + "clearCoatRoughness": { type: "f", value: 0.25 }, + + "roughness": { type: "f", value: 0.5 }, + "roughnessMap" : { type: "t", value: null }, + "roughnessOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "roughnessGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, + + "metallic": { type: "f", value: 0.5 }, + "metallicMap" : { type: "t", value: null }, + "metallicOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "metallicGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, + + "anisotropy": { type: "f", value: 0.0 }, + "anisotropyMap" : { type: "t", value: null }, + "anisotropyOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "anisotropyGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, + + "anisotropyRotation": { type: "f", value: 0.0 }, + "anisotropyRotationMap" : { type: "t", value: null }, + "anisotropyRotationOffsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, + "anisotropyRotationGainBrightness" : { type: "v4", value: new THREE.Vector4( 0, 1, 0, 1 ) }, + + "translucency" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "translucencyMap" : { type: "t", value: null }, + "translucencyNormalAlpha": { type: "f", value: 0.75 }, + "translucencyNormalPower": { type: "f", value: 2.0 }, + "translucencyViewAlpha": { type: "f", value: 0.75 }, + "translucencyViewPower": { type: "f", value: 2.0 }, + + } + + ] ), + + vertexShader: [ + + "attribute vec4 tangent;", + + "#define PHONG", + "#define PHYSICAL", + + "varying vec3 vViewPosition;", + "varying vec3 vTangent;", + "varying vec3 vBinormal;", + "varying vec3 vNormal;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "normalmap_pars_vertex" ], + THREE.ShaderChunk[ "roughnessmap_pars_vertex" ], + THREE.ShaderChunk[ "specularmap_pars_vertex" ], + THREE.ShaderChunk[ "opacitymap_pars_vertex" ], + THREE.ShaderChunk[ "anisotropymap_pars_vertex" ], + THREE.ShaderChunk[ "anisotropyrotationmap_pars_vertex" ], + THREE.ShaderChunk[ "metallicmap_pars_vertex" ], + THREE.ShaderChunk[ "translucencymap_pars_vertex" ], + THREE.ShaderChunk[ "bumpmap_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "lights_physical_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "normalmap_vertex" ], + THREE.ShaderChunk[ "roughnessmap_vertex" ], + THREE.ShaderChunk[ "opacitymap_vertex" ], + THREE.ShaderChunk[ "specularmap_vertex" ], + THREE.ShaderChunk[ "anisotropymap_vertex" ], + THREE.ShaderChunk[ "anisotropyrotationmap_vertex" ], + THREE.ShaderChunk[ "metallicmap_vertex" ], + THREE.ShaderChunk[ "translucencymap_vertex" ], + THREE.ShaderChunk[ "bumpmap_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], + + "vNormal = normalize( transformedNormal );", + + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + + "vViewPosition = -mvPosition.xyz;", + + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "lights_physical_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "#ifdef TEXTURE_CUBE_LOD_EXT", + "#extension GL_EXT_shader_texture_lod : enable", + "#endif", + "#define PHYSICAL", + "uniform vec3 diffuse;", + "uniform float opacity;", + + "uniform vec3 ambient;", + "uniform vec3 emissive;", + "uniform vec3 falloffColor;", + "uniform vec4 falloffBlendParams;", + "uniform vec3 specular;", + "uniform float roughness;", + "uniform float metallic;", + "uniform float clearCoat;", + "uniform float clearCoatRoughness;", + + "uniform vec3 translucency;", + "uniform float translucencyNormalAlpha;", + "uniform float translucencyNormalPower;", + "uniform float translucencyViewPower;", + "uniform float translucencyViewAlpha;", + + "uniform float anisotropy;", + "uniform float anisotropyRotation;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "falloffmap_pars_fragment" ], + THREE.ShaderChunk[ "opacitymap_pars_fragment" ], + THREE.ShaderChunk[ "translucencymap_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "diffuseenvmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "lights_physical_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "bumpmap_pars_fragment" ], + THREE.ShaderChunk[ "normalmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + THREE.ShaderChunk[ "anisotropymap_pars_fragment" ], + THREE.ShaderChunk[ "anisotropyrotationmap_pars_fragment" ], + THREE.ShaderChunk[ "metallicmap_pars_fragment" ], + THREE.ShaderChunk[ "roughnessmap_pars_fragment" ], + THREE.ShaderChunk[ "reflectivitymap_pars_fragment" ], + THREE.ShaderChunk[ "lightattenuation_func_fragment" ], + + "void main() {", + + "gl_FragColor = vec4( vec3 ( 0.0 ), opacity );", + "vec3 diffuseColor = diffuse;", + "vec3 translucencyColor = translucency;", + "vec3 normal = normalize( vNormal );", + "vec3 viewDirection = normalize( vViewPosition );", + + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "opacitymap_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], + THREE.ShaderChunk[ "anisotropymap_fragment" ], + THREE.ShaderChunk[ "anisotropyrotationmap_fragment" ], + THREE.ShaderChunk[ "roughnessmap_fragment" ], + THREE.ShaderChunk[ "metallicmap_fragment" ], + THREE.ShaderChunk[ "translucencymap_fragment" ], + THREE.ShaderChunk[ "reflectivitymap_fragment" ], + + THREE.ShaderChunk[ "lights_physical_fragment" ], + + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + + THREE.ShaderChunk[ "fog_fragment" ], + + "gl_FragColor.xyz *= gl_FragColor.w;", // premultipled, must be used with CustomBlender, OneFactor, OneMinusSrcAlphaFactor, AddEquation. + + "}" + + ].join("\n") + + }, + + 'basic': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "shadowmap" ] + + ] ), + + vertexShader: [ + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + + "#ifdef USE_ENVMAP", + + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], + + "#endif", + + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform vec3 diffuse;", + "uniform float opacity;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + + "void main() {", + + "gl_FragColor = vec4( diffuse, opacity );", + + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'lambert': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], + + { + "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + } + + ] ), + + vertexShader: [ + + "#define LAMBERT", + + "varying vec3 vLightFront;", + + "#ifdef DOUBLE_SIDED", + + "varying vec3 vLightBack;", + + "#endif", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "lights_lambert_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + THREE.ShaderChunk[ "lightattenuation_func_fragment" ], + + "void main() {", + + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], + + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "lights_lambert_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform float opacity;", + + "varying vec3 vLightFront;", + + "#ifdef DOUBLE_SIDED", + + "varying vec3 vLightBack;", + + "#endif", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + + "void main() {", + + "gl_FragColor = vec4( vec3 ( 1.0 ), opacity );", + + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], + + "#ifdef DOUBLE_SIDED", + + //"float isFront = float( gl_FrontFacing );", + //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", + + "if ( gl_FrontFacing )", + "gl_FragColor.xyz *= vLightFront;", + "else", + "gl_FragColor.xyz *= vLightBack;", + + "#else", + + "gl_FragColor.xyz *= vLightFront;", + + "#endif", + + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'phong': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "bumpmap" ], + THREE.UniformsLib[ "normalmap" ], + THREE.UniformsLib[ "specularmap" ], + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], + THREE.UniformsLib[ "opacitymap" ], + + { + "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, + "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, + "specular" : { type: "c", value: new THREE.Color( 0x111111 ) }, + "shininess": { type: "f", value: 30 }, + "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + } + + ] ), + + vertexShader: [ + + "#define PHONG", + + "varying vec3 vViewPosition;", + "varying vec3 vNormal;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "map_pars_vertex" ], + THREE.ShaderChunk[ "normalmap_pars_vertex" ], + THREE.ShaderChunk[ "bumpmap_pars_vertex" ], + THREE.ShaderChunk[ "specularmap_pars_vertex" ], + THREE.ShaderChunk[ "opacitymap_pars_vertex" ], + THREE.ShaderChunk[ "lightmap_pars_vertex" ], + THREE.ShaderChunk[ "lights_phong_pars_vertex" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "map_vertex" ], + THREE.ShaderChunk[ "normalmap_vertex" ], + THREE.ShaderChunk[ "bumpmap_vertex" ], + THREE.ShaderChunk[ "opacitymap_vertex" ], + THREE.ShaderChunk[ "specularmap_vertex" ], + THREE.ShaderChunk[ "lightmap_vertex" ], + THREE.ShaderChunk[ "color_vertex" ], + + THREE.ShaderChunk[ "morphnormal_vertex" ], + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + THREE.ShaderChunk[ "defaultnormal_vertex" ], + + "vNormal = normalize( transformedNormal );", + + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + + "vViewPosition = -mvPosition.xyz;", + + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "lights_phong_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "#define PHONG", + + "uniform vec3 diffuse;", + "uniform float opacity;", + + "uniform vec3 ambient;", + "uniform vec3 emissive;", + "uniform vec3 specular;", + "uniform float shininess;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_pars_fragment" ], + THREE.ShaderChunk[ "opacitymap_pars_fragment" ], + THREE.ShaderChunk[ "lightmap_pars_fragment" ], + THREE.ShaderChunk[ "envmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "lights_phong_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "bumpmap_pars_fragment" ], + THREE.ShaderChunk[ "normalmap_pars_fragment" ], + THREE.ShaderChunk[ "specularmap_pars_fragment" ], + THREE.ShaderChunk[ "lightattenuation_func_fragment" ], + + "void main() {", + + "gl_FragColor = vec4( vec3 ( 1.0 ), opacity );", + "vec3 diffuseColor = diffuse;", + + THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "opacitymap_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "specularmap_fragment" ], + + THREE.ShaderChunk[ "lights_phong_fragment" ], + + THREE.ShaderChunk[ "lightmap_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "envmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'particle_basic': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "particle" ], + THREE.UniformsLib[ "shadowmap" ] + + ] ), + + vertexShader: [ + + "uniform float size;", + "uniform float scale;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "color_vertex" ], + + "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + + "#ifdef USE_SIZEATTENUATION", + "gl_PointSize = size * ( scale / length( mvPosition.xyz ) );", + "#else", + "gl_PointSize = size;", + "#endif", + + "gl_Position = projectionMatrix * mvPosition;", + + THREE.ShaderChunk[ "worldpos_vertex" ], + THREE.ShaderChunk[ "shadowmap_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform vec3 psColor;", + "uniform float opacity;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "map_particle_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + + "void main() {", + + "gl_FragColor = vec4( psColor, opacity );", + + THREE.ShaderChunk[ "map_particle_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'dashed': { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "common" ], + THREE.UniformsLib[ "fog" ], + + { + "scale": { type: "f", value: 1 }, + "dashSize": { type: "f", value: 1 }, + "totalSize": { type: "f", value: 2 } + } + + ] ), + + vertexShader: [ + + "uniform float scale;", + "attribute float lineDistance;", + + "varying float vLineDistance;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "color_vertex" ], + + "vLineDistance = scale * lineDistance;", + + "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", + "gl_Position = projectionMatrix * mvPosition;", + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform vec3 diffuse;", + "uniform float opacity;", + + "uniform float dashSize;", + "uniform float totalSize;", + + "varying float vLineDistance;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "color_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + + "void main() {", + + "if ( mod( vLineDistance, totalSize ) > dashSize ) {", + + "discard;", + + "}", + + "gl_FragColor = vec4( diffuse, opacity );", + + THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n") + + }, + + 'depth': { + + uniforms: { + + "mNear": { type: "f", value: 1.0 }, + "mFar" : { type: "f", value: 2000.0 }, + "opacity" : { type: "f", value: 1.0 } + + }, + + vertexShader: [ + + "void main() {", + + "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform float mNear;", + "uniform float mFar;", + "uniform float opacity;", + + "void main() {", + + "float depth = gl_FragCoord.z / gl_FragCoord.w;", + "float color = clamp( ( depth - mNear ) / ( mFar - mNear ), 0.0, 1.0 );", + "gl_FragColor = vec4( vec3( color ), opacity );", + + "}" + + ].join("\n") + + }, + + 'normal': { + + uniforms: { + + "opacity" : { type: "f", value: 1.0 } + + }, + + vertexShader: [ + + "varying vec3 vNormal;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + + "void main() {", + + "vNormal = normalize( normalMatrix * normal );", + + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform float opacity;", + "varying vec3 vNormal;", + + "void main() {", + + "gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );", + + "}" + + ].join("\n") + + }, + + /* ------------------------------------------------------------------------- + // Normal map shader + // - Blinn-Phong + // - normal + diffuse + specular + AO + displacement + reflection + shadow maps + // - point and directional lights (use with "lights: true" material option) + ------------------------------------------------------------------------- */ + + 'normalmap' : { + + uniforms: THREE.UniformsUtils.merge( [ + + THREE.UniformsLib[ "fog" ], + THREE.UniformsLib[ "lights" ], + THREE.UniformsLib[ "shadowmap" ], + + { + + "enableAO" : { type: "i", value: 0 }, + "enableDiffuse" : { type: "i", value: 0 }, + "enableSpecular" : { type: "i", value: 0 }, + "enableReflection": { type: "i", value: 0 }, + "enableDisplacement": { type: "i", value: 0 }, + + "tDisplacement": { type: "t", value: null }, // must go first as this is vertex texture + "tDiffuse" : { type: "t", value: null }, + "tCube" : { type: "t", value: null }, + "tNormal" : { type: "t", value: null }, + "tSpecular" : { type: "t", value: null }, + "tAO" : { type: "t", value: null }, + + "uNormalScale": { type: "v2", value: new THREE.Vector2( 1, 1 ) }, + + "uDisplacementBias": { type: "f", value: 0.0 }, + "uDisplacementScale": { type: "f", value: 1.0 }, + + "diffuse": { type: "c", value: new THREE.Color( 0xffffff ) }, + "specular": { type: "c", value: new THREE.Color( 0x111111 ) }, + "ambient": { type: "c", value: new THREE.Color( 0xffffff ) }, + "shininess": { type: "f", value: 30 }, + "opacity": { type: "f", value: 1 }, + + "useRefract": { type: "i", value: 0 }, + "refractionRatio": { type: "f", value: 0.98 }, + "reflectivity": { type: "f", value: 0.5 }, + + "uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) }, + "uRepeat" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }, + + "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } + + } + + ] ), + + fragmentShader: [ + + "uniform vec3 ambient;", + "uniform vec3 diffuse;", + "uniform vec3 specular;", + "uniform float shininess;", + "uniform float opacity;", + + "uniform bool enableDiffuse;", + "uniform bool enableSpecular;", + "uniform bool enableAO;", + "uniform bool enableReflection;", + + "uniform sampler2D tDiffuse;", + "uniform sampler2D tNormal;", + "uniform sampler2D tSpecular;", + "uniform sampler2D tAO;", + + "uniform samplerCube tCube;", + + "uniform vec2 uNormalScale;", + + "uniform bool useRefract;", + "uniform float refractionRatio;", + "uniform float reflectivity;", + + "varying vec3 vTangent;", + "varying vec3 vBinormal;", + "varying vec3 vNormal;", + "varying vec2 vUv;", + + "uniform vec3 ambientLightColor;", + + "#if MAX_DIR_LIGHTS > 0", + + "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", + "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", + "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", + "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", + "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", + "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", + "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", + + "#endif", + + "#ifdef WRAP_AROUND", + + "uniform vec3 wrapRGB;", + + "#endif", + + "varying vec3 vWorldPosition;", + "varying vec3 vViewPosition;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "shadowmap_pars_fragment" ], + THREE.ShaderChunk[ "fog_pars_fragment" ], + + "void main() {", + + "gl_FragColor = vec4( vec3( 1.0 ), opacity );", + + "vec3 specularTex = vec3( 1.0 );", + + "vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;", + "normalTex.xy *= uNormalScale;", + "normalTex = normalize( normalTex );", + + "if( enableDiffuse ) {", + + "#ifdef GAMMA_INPUT", + + "vec4 texelColor = texture2D( tDiffuse, vUv );", + "texelColor.xyz *= texelColor.xyz;", + + "gl_FragColor = gl_FragColor * texelColor;", + + "#else", + + "gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );", + + "#endif", + + "}", + + "if( enableAO ) {", + + "#ifdef GAMMA_INPUT", + + "vec4 aoColor = texture2D( tAO, vUv );", + "aoColor.xyz *= aoColor.xyz;", + + "gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;", + + "#else", + + "gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;", + + "#endif", + + "}", + + "if( enableSpecular )", + "specularTex = texture2D( tSpecular, vUv ).xyz;", + + "mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );", + "vec3 finalNormal = tsb * normalTex;", + + "#ifdef FLIP_SIDED", + + "finalNormal = -finalNormal;", + + "#endif", + + "vec3 normal = normalize( finalNormal );", + "vec3 viewDirection = normalize( vViewPosition );", + + // point lights + + "#if MAX_POINT_LIGHTS > 0", + + "vec3 pointDiffuse = vec3( 0.0 );", + "vec3 pointSpecular = vec3( 0.0 );", + + "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", + "vec3 pointVector = lPosition.xyz + vViewPosition.xyz;", + + "float pointDistance = 1.0;", + "if ( pointLightDistance[ i ] > 0.0 )", + "pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );", + + "pointVector = normalize( pointVector );", + + // diffuse + + "#ifdef WRAP_AROUND", + + "float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );", + "float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );", + + "vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );", + + "#else", + + "float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );", + + "#endif", + + "pointDiffuse += pointDistance * pointLightColor[ i ] * diffuse * pointDiffuseWeight;", + + // specular + + "vec3 pointHalfVector = normalize( pointVector + viewDirection );", + "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", + "float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );", + "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;", + + "}", + + "#endif", + + // spot lights + + "#if MAX_SPOT_LIGHTS > 0", + + "vec3 spotDiffuse = vec3( 0.0 );", + "vec3 spotSpecular = vec3( 0.0 );", + + "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", + + "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", + "vec3 spotVector = lPosition.xyz + vViewPosition.xyz;", + + "float spotDistance = 1.0;", + "if ( spotLightDistance[ i ] > 0.0 )", + "spotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );", + + "spotVector = normalize( spotVector );", + + "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", + + "if ( spotEffect > spotLightAngleCos[ i ] ) {", + + "spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", + + // diffuse + + "#ifdef WRAP_AROUND", + + "float spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );", + "float spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );", + + "vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", + + "#else", + + "float spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );", + + "#endif", + + "spotDiffuse += spotDistance * spotLightColor[ i ] * diffuse * spotDiffuseWeight * spotEffect;", + + // specular + + "vec3 spotHalfVector = normalize( spotVector + viewDirection );", + "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", + "float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, shininess ), 0.0 );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );", + "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;", + + "}", + + "}", + + "#endif", + + // directional lights + + "#if MAX_DIR_LIGHTS > 0", + + "vec3 dirDiffuse = vec3( 0.0 );", + "vec3 dirSpecular = vec3( 0.0 );", + + "for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {", + + "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", + "vec3 dirVector = normalize( lDirection.xyz );", + + // diffuse + + "#ifdef WRAP_AROUND", + + "float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );", + "float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );", + + "vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );", + + "#else", + + "float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );", + + "#endif", + + "dirDiffuse += directionalLightColor[ i ] * diffuse * dirDiffuseWeight;", + + // specular + + "vec3 dirHalfVector = normalize( dirVector + viewDirection );", + "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", + "float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, shininess ), 0.0 );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );", + "dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", + + "}", + + "#endif", + + // hemisphere lights + + "#if MAX_HEMI_LIGHTS > 0", + + "vec3 hemiDiffuse = vec3( 0.0 );", + "vec3 hemiSpecular = vec3( 0.0 );" , + + "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", + + "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", + "vec3 lVector = normalize( lDirection.xyz );", + + // diffuse + + "float dotProduct = dot( normal, lVector );", + "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", + + "vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", + + "hemiDiffuse += diffuse * hemiColor;", + + // specular (sky light) + + + "vec3 hemiHalfVectorSky = normalize( lVector + viewDirection );", + "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", + "float hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", + + // specular (ground light) + + "vec3 lVectorGround = -lVector;", + + "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewDirection );", + "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", + "float hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", + + "float dotProductGround = dot( normal, lVectorGround );", + + // 2.0 => 2.0001 is hack to work around ANGLE bug + + "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", + + "vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );", + "vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );", + "hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", + + "}", + + "#endif", + + // all lights contribution summation + + "vec3 totalDiffuse = vec3( 0.0 );", + "vec3 totalSpecular = vec3( 0.0 );", + + "#if MAX_DIR_LIGHTS > 0", + + "totalDiffuse += dirDiffuse;", + "totalSpecular += dirSpecular;", + + "#endif", + + "#if MAX_HEMI_LIGHTS > 0", + + "totalDiffuse += hemiDiffuse;", + "totalSpecular += hemiSpecular;", + + "#endif", + + "#if MAX_POINT_LIGHTS > 0", + + "totalDiffuse += pointDiffuse;", + "totalSpecular += pointSpecular;", + + "#endif", + + "#if MAX_SPOT_LIGHTS > 0", + + "totalDiffuse += spotDiffuse;", + "totalSpecular += spotSpecular;", + + "#endif", + + "#ifdef METAL", + + "gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient + totalSpecular );", + + "#else", + + "gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient ) + totalSpecular;", + + "#endif", + + "if ( enableReflection ) {", + + "vec3 vReflect;", + "vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", + + "if ( useRefract ) {", + + "vReflect = refract( cameraToVertex, normal, refractionRatio );", + + "} else {", + + "vReflect = reflect( cameraToVertex, normal );", + + "}", + + "vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );", + + "#ifdef GAMMA_INPUT", + + "cubeColor.xyz *= cubeColor.xyz;", + + "#endif", + + "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * reflectivity );", + + "}", + + THREE.ShaderChunk[ "shadowmap_fragment" ], + THREE.ShaderChunk[ "linear_to_gamma_fragment" ], + THREE.ShaderChunk[ "fog_fragment" ], + + "}" + + ].join("\n"), + + vertexShader: [ + + "attribute vec4 tangent;", + + "uniform vec2 uOffset;", + "uniform vec2 uRepeat;", + + "uniform bool enableDisplacement;", + + "#ifdef VERTEX_TEXTURES", + + "uniform sampler2D tDisplacement;", + "uniform float uDisplacementScale;", + "uniform float uDisplacementBias;", + + "#endif", + + "varying vec3 vTangent;", + "varying vec3 vBinormal;", + "varying vec3 vNormal;", + "varying vec2 vUv;", + + "varying vec3 vWorldPosition;", + "varying vec3 vViewPosition;", + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + THREE.ShaderChunk[ "shadowmap_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "skinnormal_vertex" ], + + // normal, tangent and binormal vectors + + "#ifdef USE_SKINNING", + + "vNormal = normalize( normalMatrix * skinnedNormal.xyz );", + + "vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );", + "vTangent = normalize( normalMatrix * skinnedTangent.xyz );", + + "#else", + + "vNormal = normalize( normalMatrix * normal );", + "vTangent = normalize( normalMatrix * tangent.xyz );", + + "#endif", + + "vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );", + + "vUv = uv * uRepeat + uOffset;", + + // displacement mapping + + "vec3 displacedPosition;", + + "#ifdef VERTEX_TEXTURES", + + "if ( enableDisplacement ) {", + + "vec3 dv = texture2D( tDisplacement, uv ).xyz;", + "float df = uDisplacementScale * dv.x + uDisplacementBias;", + "displacedPosition = position + normalize( normal ) * df;", + + "} else {", + + "#ifdef USE_SKINNING", + + "vec4 skinVertex = vec4( position, 1.0 );", + + "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", + "skinned += boneMatY * skinVertex * skinWeight.y;", + + "displacedPosition = skinned.xyz;", + + "#else", + + "displacedPosition = position;", + + "#endif", + + "}", + + "#else", + + "#ifdef USE_SKINNING", + + "vec4 skinVertex = vec4( position, 1.0 );", + + "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", + "skinned += boneMatY * skinVertex * skinWeight.y;", + + "displacedPosition = skinned.xyz;", + + "#else", + + "displacedPosition = position;", + + "#endif", + + "#endif", + + // + + "vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );", + "vec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );", + + "gl_Position = projectionMatrix * mvPosition;", + + // + + "vWorldPosition = worldPosition.xyz;", + "vViewPosition = -mvPosition.xyz;", + + // shadows + + "#ifdef USE_SHADOWMAP", + + "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", + + "vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", + + "}", + + "#endif", + + "}" + + ].join("\n") + + }, + + /* ------------------------------------------------------------------------- + // Cube map shader + ------------------------------------------------------------------------- */ + + 'cube': { + + uniforms: { "tCube": { type: "t", value: null }, + "tFlip": { type: "f", value: -1 }, + "tEncoding": { type: "i", value: 0 }, + "blurring": { type: "f", value: 0 } + }, + + vertexShader: [ + + "varying vec3 vWorldPosition;", + + "void main() {", + + "vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", + "vWorldPosition = worldPosition.xyz;", + + "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + + "}" + + ].join("\n"), + + fragmentShader: [ + + "#ifdef TEXTURE_CUBE_LOD_EXT", + "#extension GL_EXT_shader_texture_lod : enable", + "#endif", + + THREE.ShaderChunk[ "common" ], + + "uniform samplerCube tCube;", + "uniform float tFlip;", + "uniform int tEncoding;", + "uniform float blurring;", + + "varying vec3 vWorldPosition;", + + "void main() {", + + "vec3 queryVector = vec3( tFlip * vWorldPosition.x, vWorldPosition.yz );", + + "#if defined( TEXTURE_CUBE_LOD_EXT )", + + "vec4 color = textureCubeLodEXT( tCube, queryVector, blurring );", + + "#else", + + "vec4 color = textureCube( tCube, queryVector );", + + "#endif", + + "color = texelDecode( color, tEncoding );", + + "#ifdef GAMMA_OUTPUT", + + "color.xyz = sqrt( color.xyz );", + + "#endif", + + "gl_FragColor = color;", + + "}" + + ].join("\n") + + }, + + // Depth encoding into RGBA texture + // based on SpiderGL shadow map example + // http://spidergl.org/example.php?id=6 + // originally from + // http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD + // see also here: + // http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ + + 'depthRGBA': { + + uniforms: {}, + + vertexShader: [ + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + + "void main() {", + + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + + "}" + + ].join("\n"), + + fragmentShader: [ + + "vec4 pack_depth( const float depth ) {", + + " const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", + " const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", + " vec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );", // " vec4 res = fract( depth * bit_shift );", + " res -= res.xxyz * bit_mask;", + " return res;", + + "}", + + "void main() {", + + "gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );", + + //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );", + //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );", + //"gl_FragData[ 0 ] = pack_depth( z );", + //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", + + "}" + + ].join("\n") + + }, + + // Depth encoding into RGBA texture + // based on SpiderGL shadow map example + // http://spidergl.org/example.php?id=6 + // originally from + // http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD + // see also here: + // http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ + + 'linearDepthRGBA': { + + uniforms: { + "zNear": { type: "f", value: 0.5 }, + "zFar": { type: "f", value: 1000 } + }, + + vertexShader: [ + + THREE.ShaderChunk[ "common" ], + THREE.ShaderChunk[ "morphtarget_pars_vertex" ], + THREE.ShaderChunk[ "skinning_pars_vertex" ], + + "varying vec3 vViewPosition;", + + "void main() {", + + THREE.ShaderChunk[ "skinbase_vertex" ], + THREE.ShaderChunk[ "morphtarget_vertex" ], + THREE.ShaderChunk[ "skinning_vertex" ], + THREE.ShaderChunk[ "default_vertex" ], + + "vViewPosition = -mvPosition.xyz;", + + "}" + + ].join("\n"), + + fragmentShader: [ + + "uniform float zNear;", + "uniform float zFar;", + + "varying vec3 vViewPosition;", + + "vec4 pack_depth( const float depth ) {", + + " const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", + " const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", + " vec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );", // " vec4 res = fract( depth * bit_shift );", + " res -= res.xxyz * bit_mask;", + " return res;", + + "}", + + "void main() {", + + "gl_FragColor = pack_depth( clamp( ( vViewPosition.z - zNear ) / ( zFar - zNear ), 0.0, 1.0 ) );", + + //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );", + //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );", + //"gl_FragData[ 0 ] = pack_depth( z );", + //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", + + "}" + + ].join("\n") + + } + +}; + +/** + * @author supereggbert / http://www.paulbrunt.co.uk/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author szimek / https://github.com/szimek/ + * @author bhouston / http://clara.io/ + */ + +THREE.WebGLRenderer = function ( parameters ) { + + console.log( 'THREE.WebGLRenderer', THREE.REVISION ); + + parameters = parameters || {}; + + var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), + _context = parameters.context !== undefined ? parameters.context : null, + + _precision = parameters.precision !== undefined ? parameters.precision : 'mediump', + + _buffers = {}, + + _alpha = parameters.alpha !== undefined ? parameters.alpha : false, + _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, + _antialias = parameters.antialias !== undefined ? parameters.antialias : false, + _stencil = parameters.stencil !== undefined ? parameters.stencil : true, + _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, + + _clearColor = new THREE.Color( 0x000000 ), + _clearAlpha = 0; + + // public properties + + this.domElement = _canvas; + this.context = null; + this.devicePixelRatio = parameters.devicePixelRatio !== undefined + ? parameters.devicePixelRatio + : self.devicePixelRatio !== undefined + ? self.devicePixelRatio + : 1; + + // clearing + + this.autoClear = true; + this.autoClearColor = true; + this.autoClearDepth = true; + this.autoClearStencil = true; + + // scene graph + + this.sortObjects = true; + this.autoUpdateObjects = true; + + // physically based shading + + this.gammaInput = true; + this.gammaOutput = true; + + // shadow map + + this.shadowMapEnabled = false; + this.shadowMapAutoUpdate = true; + this.shadowMapType = THREE.PCFShadowMap; + this.shadowMapCullFace = THREE.CullFaceFront; + this.shadowMapDebug = false; + this.shadowMapCascade = false; + + // morphs + + this.maxMorphTargets = 8; + this.maxMorphNormals = 4; + + // flags + + this.autoScaleCubemaps = true; + + // custom render plugins + + this.renderPluginsPre = []; + this.renderPluginsPost = []; + + // info + + this.info = { + + memory: { + + programs: 0, + geometries: 0, + textures: 0 + + }, + + render: { + + calls: 0, + vertices: 0, + faces: 0, + points: 0 + + } + + }; + + // internal properties + + var _this = this, + + _programs = [], + _programs_counter = 0, + + // internal state cache + + _currentProgram = null, + _currentFramebuffer = null, + _currentMaterialId = -1, + _currentGeometryGroupHash = null, + _currentCamera = null, + + _usedTextureUnits = 0, + + // GL state cache + + _oldDoubleSided = -1, + _oldFlipSided = -1, + + _oldBlending = -1, + + _oldBlendEquation = -1, + _oldBlendSrc = -1, + _oldBlendDst = -1, + + _oldDepthTest = -1, + _oldDepthWrite = -1, + + _oldPolygonOffset = null, + _oldPolygonOffsetFactor = null, + _oldPolygonOffsetUnits = null, + + _oldLineWidth = null, + + _viewportX = 0, + _viewportY = 0, + _viewportWidth = _canvas.width, + _viewportHeight = _canvas.height, + _currentWidth = 0, + _currentHeight = 0, + + _enabledAttributes = new Uint8Array( 16 ), + + // frustum + + _frustum = new THREE.Frustum(), + + // camera matrices cache + + _projScreenMatrix = new THREE.Matrix4(), + _projScreenMatrixPS = new THREE.Matrix4(), + + _vector3 = new THREE.Vector3(), + _width = new THREE.Vector3(), + _height = new THREE.Vector3(), + + // light arrays cache + + _direction = new THREE.Vector3(), + + _lightsNeedUpdate = true, + + _lights = { + + ambient: [ 0, 0, 0 ], + directional: { length: 0, colors: new Array(), positions: new Array() }, + point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), decayExponents: new Array() }, + spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), decayExponents: new Array(), directions: new Array(), anglesCos: new Array(), exponents: new Array() }, + hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() }, + area: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), decayExponents: new Array(), widths: new Array(), heights: new Array() } + + }; + + // initialize + + var _gl; + + var _glExtensionTextureFloat; + var _glExtensionTextureFloatLinear; + var _glExtensionStandardDerivatives; + var _glExtensionShaderTextureLOD; + var _glExtensionTextureFilterAnisotropic; + var _glExtensionCompressedTextureS3TC; + + initGL(); + + setDefaultGLState(); + + this.context = _gl; + + // GPU capabilities + + var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS ); + var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); + var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE ); + var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE ); + + var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0; + + var _supportsVertexTextures = ( _maxVertexTextures > 0 ); + var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat; + + var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : []; + + // + + var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT ); + var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT ); + var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT ); + + var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT ); + var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT ); + var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT ); + + var _vertexShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_INT ); + var _vertexShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_INT ); + var _vertexShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_INT ); + + var _fragmentShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_INT ); + var _fragmentShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_INT ); + var _fragmentShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_INT ); + + // clamp precision to maximum available + + var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0; + var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0; + + if ( _precision === "highp" && ! highpAvailable ) { + + if ( mediumpAvailable ) { + + _precision = "mediump"; + THREE.onwarning( "WebGLRenderer: highp not supported, using mediump" ); + + } else { + + _precision = "lowp"; + THREE.onwarning( "WebGLRenderer: highp and mediump not supported, using lowp" ); + + } + + } + + if ( _precision === "mediump" && ! mediumpAvailable ) { + + _precision = "lowp"; + THREE.onwarning( "WebGLRenderer: mediump not supported, using lowp" ); + + } + + // API + + this.getContext = function () { + + return _gl; + + }; + + this.supportsVertexTextures = function () { + + return _supportsVertexTextures; + + }; + + this.supportsFloatTextures = function () { + + return _glExtensionTextureFloat; + + }; + + this.supportsStandardDerivatives = function () { + + return _glExtensionStandardDerivatives; + + }; + + this.supportsCompressedTextureS3TC = function () { + + return _glExtensionCompressedTextureS3TC; + + }; + + this.getMaxAnisotropy = function () { + + return _maxAnisotropy; + + }; + + this.getPrecision = function () { + + return _precision; + + }; + + this.setSize = function ( width, height, updateStyle ) { + + _canvas.width = width * this.devicePixelRatio; + _canvas.height = height * this.devicePixelRatio; + + if ( this.devicePixelRatio !== 1 && updateStyle !== false ) { + + _canvas.style.width = width + 'px'; + _canvas.style.height = height + 'px'; + + } + + this.setViewport( 0, 0, width, height ); + + }; + + this.setViewport = function ( x, y, width, height ) { + + _viewportX = x * this.devicePixelRatio; + _viewportY = y * this.devicePixelRatio; + + _viewportWidth = width * this.devicePixelRatio; + _viewportHeight = height * this.devicePixelRatio; + + _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); + + }; + + this.setScissor = function ( x, y, width, height ) { + + _gl.scissor( + x * this.devicePixelRatio, + y * this.devicePixelRatio, + width * this.devicePixelRatio, + height * this.devicePixelRatio + ); + + }; + + this.enableScissorTest = function ( enable ) { + + enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST ); + + }; + + // Clearing + + this.setClearColor = function ( color, alpha ) { + + _clearColor.set( color ); + _clearAlpha = alpha !== undefined ? alpha : 1; + + _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + + }; + + this.setClearColorHex = function ( hex, alpha ) { + + THREE.onwarning( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); + this.setClearColor( hex, alpha ); + + }; + + this.getClearColor = function () { + + return _clearColor; + + }; + + this.getClearAlpha = function () { + + return _clearAlpha; + + }; + + this.clear = function ( color, depth, stencil ) { + + var bits = 0; + + if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT; + if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT; + if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT; + + _gl.clear( bits ); + + }; + + this.clearColor = function () { + + _gl.clear( _gl.COLOR_BUFFER_BIT ); + + }; + + this.clearDepth = function () { + + _gl.clear( _gl.DEPTH_BUFFER_BIT ); + + }; + + this.clearStencil = function () { + + _gl.clear( _gl.STENCIL_BUFFER_BIT ); + + }; + + this.clearTarget = function ( renderTarget, color, depth, stencil ) { + + this.setRenderTarget( renderTarget ); + this.clear( color, depth, stencil ); + + }; + + // Plugins + + this.addPostPlugin = function ( plugin ) { + + plugin.init( this ); + this.renderPluginsPost.push( plugin ); + + }; + + this.addPrePlugin = function ( plugin ) { + + plugin.init( this ); + this.renderPluginsPre.push( plugin ); + + }; + + // Rendering + + this.updateShadowMap = function ( scene, camera ) { + + _currentProgram = null; + _oldBlending = -1; + _oldDepthTest = -1; + _oldDepthWrite = -1; + _currentGeometryGroupHash = -1; + _currentMaterialId = -1; + _lightsNeedUpdate = true; + _oldDoubleSided = -1; + _oldFlipSided = -1; + + this.shadowMapPlugin.update( scene, camera ); + + }; + + // Internal functions + + // Buffer allocation + + function createParticleBuffers ( geometry ) { + + geometry.__webglVertexBuffer = _gl.createBuffer(); + geometry.__webglColorBuffer = _gl.createBuffer(); + + _this.info.memory.geometries ++; + + }; + + function createLineBuffers ( geometry ) { + + geometry.__webglVertexBuffer = _gl.createBuffer(); + geometry.__webglColorBuffer = _gl.createBuffer(); + geometry.__webglLineDistanceBuffer = _gl.createBuffer(); + + _this.info.memory.geometries ++; + + }; + + function createMeshBuffers ( geometryGroup ) { + + geometryGroup.__webglVertexBuffer = _gl.createBuffer(); + geometryGroup.__webglNormalBuffer = _gl.createBuffer(); + geometryGroup.__webglTangentBuffer = _gl.createBuffer(); + geometryGroup.__webglColorBuffer = _gl.createBuffer(); + geometryGroup.__webglUVBuffer = _gl.createBuffer(); + geometryGroup.__webglUV2Buffer = _gl.createBuffer(); + + geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer(); + geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer(); + + geometryGroup.__webglFaceBuffer = _gl.createBuffer(); + geometryGroup.__webglLineBuffer = _gl.createBuffer(); + + var m, ml; + + if ( geometryGroup.numMorphTargets ) { + + geometryGroup.__webglMorphTargetsBuffers = []; + + for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + + geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() ); + + } + + } + + if ( geometryGroup.numMorphNormals ) { + + geometryGroup.__webglMorphNormalsBuffers = []; + + for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + + geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() ); + + } + + } + + _this.info.memory.geometries ++; + + }; + + // Events + + var onGeometryDispose = function ( event ) { + + var geometry = event.target; + + geometry.removeEventListener( 'dispose', onGeometryDispose ); + + deallocateGeometry( geometry ); + + }; + + var onTextureDispose = function ( event ) { + + var texture = event.target; + + texture.removeEventListener( 'dispose', onTextureDispose ); + + deallocateTexture( texture ); + + _this.info.memory.textures --; + + + }; + + var onRenderTargetDispose = function ( event ) { + + var renderTarget = event.target; + + renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); + + deallocateRenderTarget( renderTarget ); + + _this.info.memory.textures --; + + }; + + var onMaterialDispose = function ( event ) { + + var material = event.target; + + material.removeEventListener( 'dispose', onMaterialDispose ); + + deallocateMaterial( material ); + + }; + + // Buffer deallocation + + var deleteBuffers = function ( geometry ) { + + if ( geometry.__webglVertexBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglVertexBuffer ); + if ( geometry.__webglNormalBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglNormalBuffer ); + if ( geometry.__webglTangentBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglTangentBuffer ); + if ( geometry.__webglColorBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglColorBuffer ); + if ( geometry.__webglUVBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglUVBuffer ); + if ( geometry.__webglUV2Buffer !== undefined ) _gl.deleteBuffer( geometry.__webglUV2Buffer ); + + if ( geometry.__webglSkinIndicesBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinIndicesBuffer ); + if ( geometry.__webglSkinWeightsBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinWeightsBuffer ); + + if ( geometry.__webglFaceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglFaceBuffer ); + if ( geometry.__webglLineBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineBuffer ); + + if ( geometry.__webglLineDistanceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineDistanceBuffer ); + // custom attributes + + if ( geometry.__webglCustomAttributesList !== undefined ) { + + for ( var id in geometry.__webglCustomAttributesList ) { + + _gl.deleteBuffer( geometry.__webglCustomAttributesList[ id ].buffer ); + + } + + } + + _this.info.memory.geometries --; + + }; + + var deallocateGeometry = function ( geometry ) { + + geometry.__webglInit = undefined; + + if ( geometry instanceof THREE.BufferGeometry ) { + + var attributes = geometry.attributes; + + for ( var key in attributes ) { + + if ( attributes[ key ].buffer !== undefined ) { + + _gl.deleteBuffer( attributes[ key ].buffer ); + + } + + } + + _this.info.memory.geometries --; + + } else { + + if ( geometry.geometryGroups !== undefined ) { + + for ( var g in geometry.geometryGroups ) { + + var geometryGroup = geometry.geometryGroups[ g ]; + + if ( geometryGroup.numMorphTargets !== undefined ) { + + for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + + _gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] ); + + } + + } + + if ( geometryGroup.numMorphNormals !== undefined ) { + + for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + + _gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] ); + + } + + } + + deleteBuffers( geometryGroup ); + + } + + } else { + + deleteBuffers( geometry ); + + } + + } + + }; + + var deallocateTexture = function ( texture ) { + + if ( texture.image && texture.image.__webglTextureCube ) { + + // cube texture + + _gl.deleteTexture( texture.image.__webglTextureCube ); + + } else { + + // 2D texture + + if ( ! texture.__webglInit ) return; + + texture.__webglInit = false; + _gl.deleteTexture( texture.__webglTexture ); + + } + + }; + + var deallocateRenderTarget = function ( renderTarget ) { + + if ( !renderTarget || ! renderTarget.__webglTexture ) return; + + _gl.deleteTexture( renderTarget.__webglTexture ); + + if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { + + for ( var i = 0; i < 6; i ++ ) { + + _gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] ); + _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] ); + + } + + } else { + + _gl.deleteFramebuffer( renderTarget.__webglFramebuffer ); + _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer ); + + } + + }; + + var deallocateMaterial = function ( material, optionalDisconnectedProgram ) { + + var program = optionalDisconnectedProgram || material.program; + + if ( program === undefined ) return; + + if( ! optionalDisconnectedProgram ) { + material.program = undefined; + } + + // only deallocate GL program if this was the last use of shared program + // assumed there is only single copy of any program in the _programs list + // (that's how it's constructed) + + var i, il, programInfo; + var deleteProgram = false; + + for ( i = 0, il = _programs.length; i < il; i ++ ) { + + programInfo = _programs[ i ]; + + if ( programInfo.program === program ) { + + programInfo.usedTimes --; + + if ( programInfo.usedTimes === 0 ) { + + deleteProgram = true; + + } + + break; + + } + + } + + if ( deleteProgram === true ) { + + // avoid using array.splice, this is costlier than creating new array from scratch + + var newPrograms = []; + + for ( i = 0, il = _programs.length; i < il; i ++ ) { + + programInfo = _programs[ i ]; + + if ( programInfo.program !== program ) { + + newPrograms.push( programInfo ); + + } + + } + + _programs = newPrograms; + + _gl.deleteProgram( program ); + + _this.info.memory.programs --; + + } + + }; + + // Buffer initialization + + function initCustomAttributes ( geometry, object ) { + + var nvertices = geometry.vertices.length; + + var material = object.material; + + if ( material.attributes ) { + + if ( geometry.__webglCustomAttributesList === undefined ) { + + geometry.__webglCustomAttributesList = []; + + } + + for ( var a in material.attributes ) { + + var attribute = material.attributes[ a ]; + + if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { + + attribute.__webglInitialized = true; + + var size = 1; // "f" and "i" + + if ( attribute.type === "v2" ) size = 2; + else if ( attribute.type === "v3" ) size = 3; + else if ( attribute.type === "v4" ) size = 4; + else if ( attribute.type === "c" ) size = 3; + + attribute.size = size; + + attribute.array = new Float32Array( nvertices * size ); + + attribute.buffer = _gl.createBuffer(); + attribute.buffer.belongsToAttribute = a; + + attribute.needsUpdate = true; + + } + + geometry.__webglCustomAttributesList.push( attribute ); + + } + + } + + }; + + function initParticleBuffers ( geometry, object ) { + + var nvertices = geometry.vertices.length; + + geometry.__vertexArray = new Float32Array( nvertices * 3 ); + geometry.__colorArray = new Float32Array( nvertices * 3 ); + + geometry.__sortArray = []; + + geometry.__webglParticleCount = nvertices; + + initCustomAttributes ( geometry, object ); + + }; + + function initLineBuffers ( geometry, object ) { + + var nvertices = geometry.vertices.length; + + geometry.__vertexArray = new Float32Array( nvertices * 3 ); + geometry.__colorArray = new Float32Array( nvertices * 3 ); + geometry.__lineDistanceArray = new Float32Array( nvertices * 1 ); + + geometry.__webglLineCount = nvertices; + + initCustomAttributes ( geometry, object ); + + }; + + function initMeshBuffers ( geometryGroup, object ) { + + var geometry = object.geometry, + faces3 = geometryGroup.faces3, + + nvertices = faces3.length * 3, + ntris = faces3.length * 1, + nlines = faces3.length * 3, + + material = getBufferMaterial( object, geometryGroup ), + + uvType = bufferGuessUVType( material ), + normalType = bufferGuessNormalType( material ), + vertexColorType = bufferGuessVertexColorType( material ); + + geometryGroup.__vertexArray = new Float32Array( nvertices * 3 ); + + if ( normalType ) { + + geometryGroup.__normalArray = new Float32Array( nvertices * 3 ); + + } + + if ( geometry.hasTangents ) { + + geometryGroup.__tangentArray = new Float32Array( nvertices * 4 ); + + } + + if ( vertexColorType ) { + + geometryGroup.__colorArray = new Float32Array( nvertices * 3 ); + + } + + if ( uvType ) { + + if ( geometry.faceVertexUvs.length > 0 ) { + + geometryGroup.__uvArray = new Float32Array( nvertices * 2 ); + + } + + if ( geometry.faceVertexUvs.length > 1 ) { + + geometryGroup.__uv2Array = new Float32Array( nvertices * 2 ); + + } + + } + + if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) { + + geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 ); + geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 ); + + } + + geometryGroup.__faceArray = new Uint16Array( ntris * 3 ); + geometryGroup.__lineArray = new Uint16Array( nlines * 2 ); + + var m, ml; + + if ( geometryGroup.numMorphTargets ) { + + geometryGroup.__morphTargetsArrays = []; + + for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { + + geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) ); + + } + + } + + if ( geometryGroup.numMorphNormals ) { + + geometryGroup.__morphNormalsArrays = []; + + for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { + + geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) ); + + } + + } + + geometryGroup.__webglFaceCount = ntris * 3; + geometryGroup.__webglLineCount = nlines * 2; + + + // custom attributes + + if ( material.attributes ) { + + if ( geometryGroup.__webglCustomAttributesList === undefined ) { + + geometryGroup.__webglCustomAttributesList = []; + + } + + for ( var a in material.attributes ) { + + // Do a shallow copy of the attribute object so different geometryGroup chunks use different + // attribute buffers which are correctly indexed in the setMeshBuffers function + + var originalAttribute = material.attributes[ a ]; + + var attribute = {}; + + for ( var property in originalAttribute ) { + + attribute[ property ] = originalAttribute[ property ]; + + } + + if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { + + attribute.__webglInitialized = true; + + var size = 1; // "f" and "i" + + if( attribute.type === "v2" ) size = 2; + else if( attribute.type === "v3" ) size = 3; + else if( attribute.type === "v4" ) size = 4; + else if( attribute.type === "c" ) size = 3; + + attribute.size = size; + + attribute.array = new Float32Array( nvertices * size ); + + attribute.buffer = _gl.createBuffer(); + attribute.buffer.belongsToAttribute = a; + + originalAttribute.needsUpdate = true; + attribute.__original = originalAttribute; + + } + + geometryGroup.__webglCustomAttributesList.push( attribute ); + + } + + } + + geometryGroup.__inittedArrays = true; + + }; + + function getBufferMaterial( object, geometryGroup ) { + + return object.material instanceof THREE.MeshFaceMaterial + ? object.material.materials[ geometryGroup.materialIndex ] + : object.material; + + }; + + function materialNeedsSmoothNormals ( material ) { + + return material && material.shading !== undefined && material.shading === THREE.SmoothShading; + + }; + + function bufferGuessNormalType ( material ) { + + // only MeshBasicMaterial and MeshDepthMaterial don't need normals + + if ( ( material instanceof THREE.MeshBasicMaterial && !material.envMap ) || material instanceof THREE.MeshDepthMaterial ) { + + return false; + + } + + if ( materialNeedsSmoothNormals( material ) ) { + + return THREE.SmoothShading; + + } else { + + return THREE.FlatShading; + + } + + }; + + function bufferGuessVertexColorType( material ) { + + if ( material.vertexColors ) { + + return material.vertexColors; + + } + + return false; + + }; + + function bufferGuessUVType( material ) { + + // material must use some texture to require uvs + + if ( material.map || + material.opacityMap || + material.lightMap || + material.emissiveMap || + material.bumpMap || + material.normalMap || + material.specularMap || + material.reflectivityMap || + material.roughnessMap || + material.falloffMap || + material.anisotropyMap || + material.anisotropyRotationMap || + material.metallicMap || + material.translucencyMap || + ( material.anisotropy && material.anisotropy !== 0.0 ) || + material instanceof THREE.ShaderMaterial ) { + + return true; + + } + + return true; + + }; + + // + + function initDirectBuffers( geometry ) { + + var a, attribute, type; + + for ( a in geometry.attributes ) { + + if ( a === "index" ) { + + type = _gl.ELEMENT_ARRAY_BUFFER; + + } else { + + type = _gl.ARRAY_BUFFER; + + } + + attribute = geometry.attributes[ a ]; + + attribute.buffer = _gl.createBuffer(); + + _gl.bindBuffer( type, attribute.buffer ); + _gl.bufferData( type, attribute.array, _gl.STATIC_DRAW ); + + } + + }; + + // Buffer setting + + function setParticleBuffers ( geometry, hint, object ) { + + var v, c, vertex, offset, index, color, + + vertices = geometry.vertices, + vl = vertices.length, + + colors = geometry.colors, + cl = colors.length, + + vertexArray = geometry.__vertexArray, + colorArray = geometry.__colorArray, + + sortArray = geometry.__sortArray, + + dirtyVertices = geometry.verticesNeedUpdate, + dirtyElements = geometry.elementsNeedUpdate, + dirtyColors = geometry.colorsNeedUpdate, + + customAttributes = geometry.__webglCustomAttributesList, + i, il, + a, ca, cal, value, + customAttribute; + + if ( object.sortParticles ) { + + _projScreenMatrixPS.copy( _projScreenMatrix ); + _projScreenMatrixPS.multiply( object.matrixWorld ); + + for ( v = 0; v < vl; v ++ ) { + + vertex = vertices[ v ]; + + _vector3.copy( vertex ); + _vector3.applyProjection( _projScreenMatrixPS ); + + sortArray[ v ] = [ _vector3.z, v ]; + + } + + sortArray.sort( numericalSort ); + + for ( v = 0; v < vl; v ++ ) { + + vertex = vertices[ sortArray[v][1] ]; + + offset = v * 3; + + vertexArray[ offset ] = vertex.x; + vertexArray[ offset + 1 ] = vertex.y; + vertexArray[ offset + 2 ] = vertex.z; + + } + + for ( c = 0; c < cl; c ++ ) { + + offset = c * 3; + + color = colors[ sortArray[c][1] ]; + + colorArray[ offset ] = color.r; + colorArray[ offset + 1 ] = color.g; + colorArray[ offset + 2 ] = color.b; + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( ! ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) continue; + + offset = 0; + + cal = customAttribute.value.length; + + if ( customAttribute.size === 1 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + customAttribute.array[ ca ] = customAttribute.value[ index ]; + + } + + } else if ( customAttribute.size === 2 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + value = customAttribute.value[ index ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + + offset += 2; + + } + + } else if ( customAttribute.size === 3 ) { + + if ( customAttribute.type === "c" ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + value = customAttribute.value[ index ]; + + customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset + 1 ] = value.g; + customAttribute.array[ offset + 2 ] = value.b; + + offset += 3; + + } + + } else { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + value = customAttribute.value[ index ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + + offset += 3; + + } + + } + + } else if ( customAttribute.size === 4 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + index = sortArray[ ca ][ 1 ]; + + value = customAttribute.value[ index ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset + 3 ] = value.w; + + offset += 4; + + } + + } + + } + + } + + } else { + + if ( dirtyVertices ) { + + for ( v = 0; v < vl; v ++ ) { + + vertex = vertices[ v ]; + + offset = v * 3; + + vertexArray[ offset ] = vertex.x; + vertexArray[ offset + 1 ] = vertex.y; + vertexArray[ offset + 2 ] = vertex.z; + + } + + } + + if ( dirtyColors ) { + + for ( c = 0; c < cl; c ++ ) { + + color = colors[ c ]; + + offset = c * 3; + + colorArray[ offset ] = color.r; + colorArray[ offset + 1 ] = color.g; + colorArray[ offset + 2 ] = color.b; + + } + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( customAttribute.needsUpdate && + ( customAttribute.boundTo === undefined || + customAttribute.boundTo === "vertices") ) { + + cal = customAttribute.value.length; + + offset = 0; + + if ( customAttribute.size === 1 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + customAttribute.array[ ca ] = customAttribute.value[ ca ]; + + } + + } else if ( customAttribute.size === 2 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + + offset += 2; + + } + + } else if ( customAttribute.size === 3 ) { + + if ( customAttribute.type === "c" ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset + 1 ] = value.g; + customAttribute.array[ offset + 2 ] = value.b; + + offset += 3; + + } + + } else { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + + offset += 3; + + } + + } + + } else if ( customAttribute.size === 4 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset + 3 ] = value.w; + + offset += 4; + + } + + } + + } + + } + + } + + } + + if ( dirtyVertices || object.sortParticles ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + + } + + if ( dirtyColors || object.sortParticles ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( customAttribute.needsUpdate || object.sortParticles ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + + } + + } + + } + + + }; + + function setLineBuffers ( geometry, hint ) { + + var v, c, d, vertex, offset, color, + + vertices = geometry.vertices, + colors = geometry.colors, + lineDistances = geometry.lineDistances, + + vl = vertices.length, + cl = colors.length, + dl = lineDistances.length, + + vertexArray = geometry.__vertexArray, + colorArray = geometry.__colorArray, + lineDistanceArray = geometry.__lineDistanceArray, + + dirtyVertices = geometry.verticesNeedUpdate, + dirtyColors = geometry.colorsNeedUpdate, + dirtyLineDistances = geometry.lineDistancesNeedUpdate, + + customAttributes = geometry.__webglCustomAttributesList, + + i, il, + a, ca, cal, value, + customAttribute; + + if ( dirtyVertices ) { + + for ( v = 0; v < vl; v ++ ) { + + vertex = vertices[ v ]; + + offset = v * 3; + + vertexArray[ offset ] = vertex.x; + vertexArray[ offset + 1 ] = vertex.y; + vertexArray[ offset + 2 ] = vertex.z; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + + } + + if ( dirtyColors ) { + + for ( c = 0; c < cl; c ++ ) { + + color = colors[ c ]; + + offset = c * 3; + + colorArray[ offset ] = color.r; + colorArray[ offset + 1 ] = color.g; + colorArray[ offset + 2 ] = color.b; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); + + } + + if ( dirtyLineDistances ) { + + for ( d = 0; d < dl; d ++ ) { + + lineDistanceArray[ d ] = lineDistances[ d ]; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint ); + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( customAttribute.needsUpdate && + ( customAttribute.boundTo === undefined || + customAttribute.boundTo === "vertices" ) ) { + + offset = 0; + + cal = customAttribute.value.length; + + if ( customAttribute.size === 1 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + customAttribute.array[ ca ] = customAttribute.value[ ca ]; + + } + + } else if ( customAttribute.size === 2 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + + offset += 2; + + } + + } else if ( customAttribute.size === 3 ) { + + if ( customAttribute.type === "c" ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.r; + customAttribute.array[ offset + 1 ] = value.g; + customAttribute.array[ offset + 2 ] = value.b; + + offset += 3; + + } + + } else { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + + offset += 3; + + } + + } + + } else if ( customAttribute.size === 4 ) { + + for ( ca = 0; ca < cal; ca ++ ) { + + value = customAttribute.value[ ca ]; + + customAttribute.array[ offset ] = value.x; + customAttribute.array[ offset + 1 ] = value.y; + customAttribute.array[ offset + 2 ] = value.z; + customAttribute.array[ offset + 3 ] = value.w; + + offset += 4; + + } + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + + } + + } + + } + + }; + + function setMeshBuffers( geometryGroup, object, hint, dispose, material ) { + + if ( ! geometryGroup.__inittedArrays ) { + + return; + + } + + var normalType = bufferGuessNormalType( material ), + vertexColorType = bufferGuessVertexColorType( material ), + uvType = bufferGuessUVType( material ), + + needsSmoothNormals = ( normalType === THREE.SmoothShading ); + + var f, fl, fi, face, + vertexNormals, faceNormal, normal, + vertexColors, faceColor, + vertexTangents, + uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4, + c1, c2, c3, c4, + sw1, sw2, sw3, sw4, + si1, si2, si3, si4, + sa1, sa2, sa3, sa4, + sb1, sb2, sb3, sb4, + m, ml, i, il, + vn, uvi, uv2i, + vk, vkl, vka, + nka, chf, faceVertexNormals, + a, + + vertexIndex = 0, + + offset = 0, + offset_uv = 0, + offset_uv2 = 0, + offset_face = 0, + offset_normal = 0, + offset_tangent = 0, + offset_line = 0, + offset_color = 0, + offset_skin = 0, + offset_morphTarget = 0, + offset_custom = 0, + offset_customSrc = 0, + + value, + + vertexArray = geometryGroup.__vertexArray, + uvArray = geometryGroup.__uvArray, + uv2Array = geometryGroup.__uv2Array, + normalArray = geometryGroup.__normalArray, + tangentArray = geometryGroup.__tangentArray, + colorArray = geometryGroup.__colorArray, + + skinIndexArray = geometryGroup.__skinIndexArray, + skinWeightArray = geometryGroup.__skinWeightArray, + + morphTargetsArrays = geometryGroup.__morphTargetsArrays, + morphNormalsArrays = geometryGroup.__morphNormalsArrays, + + customAttributes = geometryGroup.__webglCustomAttributesList, + customAttribute, + + faceArray = geometryGroup.__faceArray, + lineArray = geometryGroup.__lineArray, + + geometry = object.geometry, // this is shared for all chunks + + dirtyVertices = geometry.verticesNeedUpdate, + dirtyElements = geometry.elementsNeedUpdate, + dirtyUvs = geometry.uvsNeedUpdate, + dirtyNormals = geometry.normalsNeedUpdate, + dirtyTangents = geometry.tangentsNeedUpdate, + dirtyColors = geometry.colorsNeedUpdate, + dirtyMorphTargets = geometry.morphTargetsNeedUpdate, + + vertices = geometry.vertices, + chunk_faces3 = geometryGroup.faces3, + obj_faces = geometry.faces, + + obj_uvs = geometry.faceVertexUvs[ 0 ], + obj_uvs2 = geometry.faceVertexUvs[ 1 ], + + obj_colors = geometry.colors, + + obj_skinIndices = geometry.skinIndices, + obj_skinWeights = geometry.skinWeights, + + morphTargets = geometry.morphTargets, + morphNormals = geometry.morphNormals; + + if ( dirtyVertices ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + v1 = vertices[ face.a ]; + v2 = vertices[ face.b ]; + v3 = vertices[ face.c ]; + + vertexArray[ offset ] = v1.x; + vertexArray[ offset + 1 ] = v1.y; + vertexArray[ offset + 2 ] = v1.z; + + vertexArray[ offset + 3 ] = v2.x; + vertexArray[ offset + 4 ] = v2.y; + vertexArray[ offset + 5 ] = v2.z; + + vertexArray[ offset + 6 ] = v3.x; + vertexArray[ offset + 7 ] = v3.y; + vertexArray[ offset + 8 ] = v3.z; + + offset += 9; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); + + } + + if ( dirtyMorphTargets ) { + + for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) { + + offset_morphTarget = 0; + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + chf = chunk_faces3[ f ]; + face = obj_faces[ chf ]; + + // morph positions + + v1 = morphTargets[ vk ].vertices[ face.a ]; + v2 = morphTargets[ vk ].vertices[ face.b ]; + v3 = morphTargets[ vk ].vertices[ face.c ]; + + vka = morphTargetsArrays[ vk ]; + + vka[ offset_morphTarget ] = v1.x; + vka[ offset_morphTarget + 1 ] = v1.y; + vka[ offset_morphTarget + 2 ] = v1.z; + + vka[ offset_morphTarget + 3 ] = v2.x; + vka[ offset_morphTarget + 4 ] = v2.y; + vka[ offset_morphTarget + 5 ] = v2.z; + + vka[ offset_morphTarget + 6 ] = v3.x; + vka[ offset_morphTarget + 7 ] = v3.y; + vka[ offset_morphTarget + 8 ] = v3.z; + + // morph normals + + if ( material.morphNormals ) { + + if ( needsSmoothNormals ) { + + faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ]; + + n1 = faceVertexNormals.a; + n2 = faceVertexNormals.b; + n3 = faceVertexNormals.c; + + } else { + + n1 = morphNormals[ vk ].faceNormals[ chf ]; + n2 = n1; + n3 = n1; + + } + + nka = morphNormalsArrays[ vk ]; + + nka[ offset_morphTarget ] = n1.x; + nka[ offset_morphTarget + 1 ] = n1.y; + nka[ offset_morphTarget + 2 ] = n1.z; + + nka[ offset_morphTarget + 3 ] = n2.x; + nka[ offset_morphTarget + 4 ] = n2.y; + nka[ offset_morphTarget + 5 ] = n2.z; + + nka[ offset_morphTarget + 6 ] = n3.x; + nka[ offset_morphTarget + 7 ] = n3.y; + nka[ offset_morphTarget + 8 ] = n3.z; + + } + + // + + offset_morphTarget += 9; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] ); + _gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint ); + + if ( material.morphNormals ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] ); + _gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint ); + + } + + } + + } + + if ( obj_skinWeights.length ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + // weights + + sw1 = obj_skinWeights[ face.a ]; + sw2 = obj_skinWeights[ face.b ]; + sw3 = obj_skinWeights[ face.c ]; + + skinWeightArray[ offset_skin ] = sw1.x; + skinWeightArray[ offset_skin + 1 ] = sw1.y; + skinWeightArray[ offset_skin + 2 ] = sw1.z; + skinWeightArray[ offset_skin + 3 ] = sw1.w; + + skinWeightArray[ offset_skin + 4 ] = sw2.x; + skinWeightArray[ offset_skin + 5 ] = sw2.y; + skinWeightArray[ offset_skin + 6 ] = sw2.z; + skinWeightArray[ offset_skin + 7 ] = sw2.w; + + skinWeightArray[ offset_skin + 8 ] = sw3.x; + skinWeightArray[ offset_skin + 9 ] = sw3.y; + skinWeightArray[ offset_skin + 10 ] = sw3.z; + skinWeightArray[ offset_skin + 11 ] = sw3.w; + + // indices + + si1 = obj_skinIndices[ face.a ]; + si2 = obj_skinIndices[ face.b ]; + si3 = obj_skinIndices[ face.c ]; + + skinIndexArray[ offset_skin ] = si1.x; + skinIndexArray[ offset_skin + 1 ] = si1.y; + skinIndexArray[ offset_skin + 2 ] = si1.z; + skinIndexArray[ offset_skin + 3 ] = si1.w; + + skinIndexArray[ offset_skin + 4 ] = si2.x; + skinIndexArray[ offset_skin + 5 ] = si2.y; + skinIndexArray[ offset_skin + 6 ] = si2.z; + skinIndexArray[ offset_skin + 7 ] = si2.w; + + skinIndexArray[ offset_skin + 8 ] = si3.x; + skinIndexArray[ offset_skin + 9 ] = si3.y; + skinIndexArray[ offset_skin + 10 ] = si3.z; + skinIndexArray[ offset_skin + 11 ] = si3.w; + + offset_skin += 12; + + } + + if ( offset_skin > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint ); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint ); + + } + + } + + if ( dirtyColors && vertexColorType ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + vertexColors = face.vertexColors; + faceColor = face.color; + + if ( vertexColors.length === 3 && vertexColorType === THREE.VertexColors ) { + + c1 = vertexColors[ 0 ]; + c2 = vertexColors[ 1 ]; + c3 = vertexColors[ 2 ]; + + } else { + + c1 = faceColor; + c2 = faceColor; + c3 = faceColor; + + } + + colorArray[ offset_color ] = c1.r; + colorArray[ offset_color + 1 ] = c1.g; + colorArray[ offset_color + 2 ] = c1.b; + + colorArray[ offset_color + 3 ] = c2.r; + colorArray[ offset_color + 4 ] = c2.g; + colorArray[ offset_color + 5 ] = c2.b; + + colorArray[ offset_color + 6 ] = c3.r; + colorArray[ offset_color + 7 ] = c3.g; + colorArray[ offset_color + 8 ] = c3.b; + + offset_color += 9; + + } + + if ( offset_color > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); + + } + + } + + if ( dirtyTangents && geometry.hasTangents ) { + + var tmp = new THREE.Vector3( 0, 0, 0 ); + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + vertexTangents = face.vertexTangents; + + t1 = vertexTangents[ 0 ] || tmp; + t2 = vertexTangents[ 1 ] || tmp; + t3 = vertexTangents[ 2 ] || tmp; + + tangentArray[ offset_tangent ] = t1.x; + tangentArray[ offset_tangent + 1 ] = t1.y; + tangentArray[ offset_tangent + 2 ] = t1.z; + tangentArray[ offset_tangent + 3 ] = t1.w; + + tangentArray[ offset_tangent + 4 ] = t2.x; + tangentArray[ offset_tangent + 5 ] = t2.y; + tangentArray[ offset_tangent + 6 ] = t2.z; + tangentArray[ offset_tangent + 7 ] = t2.w; + + tangentArray[ offset_tangent + 8 ] = t3.x; + tangentArray[ offset_tangent + 9 ] = t3.y; + tangentArray[ offset_tangent + 10 ] = t3.z; + tangentArray[ offset_tangent + 11 ] = t3.w; + + offset_tangent += 12; + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint ); + + } + + if ( dirtyNormals && normalType ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + vertexNormals = face.vertexNormals; + faceNormal = face.normal; + + if ( vertexNormals.length === 3 && needsSmoothNormals ) { + + for ( i = 0; i < 3; i ++ ) { + + vn = vertexNormals[ i ]; + + normalArray[ offset_normal ] = vn.x; + normalArray[ offset_normal + 1 ] = vn.y; + normalArray[ offset_normal + 2 ] = vn.z; + + offset_normal += 3; + + } + + } else { + + for ( i = 0; i < 3; i ++ ) { + + normalArray[ offset_normal ] = faceNormal.x; + normalArray[ offset_normal + 1 ] = faceNormal.y; + normalArray[ offset_normal + 2 ] = faceNormal.z; + + offset_normal += 3; + + } + + } + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint ); + + } + + if ( dirtyUvs && obj_uvs && uvType ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + fi = chunk_faces3[ f ]; + + uv = obj_uvs[ fi ]; + + if ( uv === undefined ) continue; + + for ( i = 0; i < 3; i ++ ) { + + uvi = uv[ i ]; + + uvArray[ offset_uv ] = uvi.x; + uvArray[ offset_uv + 1 ] = uvi.y; + + offset_uv += 2; + + } + + } + + if ( offset_uv > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint ); + + } + + } + + if ( dirtyUvs && obj_uvs2 && uvType ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + fi = chunk_faces3[ f ]; + + uv2 = obj_uvs2[ fi ]; + + if ( uv2 === undefined ) continue; + + for ( i = 0; i < 3; i ++ ) { + + uv2i = uv2[ i ]; + + uv2Array[ offset_uv2 ] = uv2i.x; + uv2Array[ offset_uv2 + 1 ] = uv2i.y; + + offset_uv2 += 2; + + } + + } + + if ( offset_uv2 > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint ); + + } + + } + + if ( dirtyElements ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + faceArray[ offset_face ] = vertexIndex; + faceArray[ offset_face + 1 ] = vertexIndex + 1; + faceArray[ offset_face + 2 ] = vertexIndex + 2; + + offset_face += 3; + + lineArray[ offset_line ] = vertexIndex; + lineArray[ offset_line + 1 ] = vertexIndex + 1; + + lineArray[ offset_line + 2 ] = vertexIndex; + lineArray[ offset_line + 3 ] = vertexIndex + 2; + + lineArray[ offset_line + 4 ] = vertexIndex + 1; + lineArray[ offset_line + 5 ] = vertexIndex + 2; + + offset_line += 6; + + vertexIndex += 3; + + } + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint ); + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint ); + + } + + if ( customAttributes ) { + + for ( i = 0, il = customAttributes.length; i < il; i ++ ) { + + customAttribute = customAttributes[ i ]; + + if ( ! customAttribute.__original.needsUpdate ) continue; + + offset_custom = 0; + offset_customSrc = 0; + + if ( customAttribute.size === 1 ) { + + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ]; + customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ]; + customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ]; + + offset_custom += 3; + + } + + } else if ( customAttribute.boundTo === "faces" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + customAttribute.array[ offset_custom ] = value; + customAttribute.array[ offset_custom + 1 ] = value; + customAttribute.array[ offset_custom + 2 ] = value; + + offset_custom += 3; + + } + + } + + } else if ( customAttribute.size === 2 ) { + + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + + customAttribute.array[ offset_custom + 2 ] = v2.x; + customAttribute.array[ offset_custom + 3 ] = v2.y; + + customAttribute.array[ offset_custom + 4 ] = v3.x; + customAttribute.array[ offset_custom + 5 ] = v3.y; + + offset_custom += 6; + + } + + } else if ( customAttribute.boundTo === "faces" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value; + v2 = value; + v3 = value; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + + customAttribute.array[ offset_custom + 2 ] = v2.x; + customAttribute.array[ offset_custom + 3 ] = v2.y; + + customAttribute.array[ offset_custom + 4 ] = v3.x; + customAttribute.array[ offset_custom + 5 ] = v3.y; + + offset_custom += 6; + + } + + } + + } else if ( customAttribute.size === 3 ) { + + var pp; + + if ( customAttribute.type === "c" ) { + + pp = [ "r", "g", "b" ]; + + } else { + + pp = [ "x", "y", "z" ]; + + } + + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; + + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + + offset_custom += 9; + + } + + } else if ( customAttribute.boundTo === "faces" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value; + v2 = value; + v3 = value; + + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + + offset_custom += 9; + + } + + } else if ( customAttribute.boundTo === "faceVertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value[ 0 ]; + v2 = value[ 1 ]; + v3 = value[ 2 ]; + + customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; + + customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; + customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; + customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; + + offset_custom += 9; + + } + + } + + } else if ( customAttribute.size === 4 ) { + + if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + face = obj_faces[ chunk_faces3[ f ] ]; + + v1 = customAttribute.value[ face.a ]; + v2 = customAttribute.value[ face.b ]; + v3 = customAttribute.value[ face.c ]; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; + + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; + + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; + + offset_custom += 12; + + } + + } else if ( customAttribute.boundTo === "faces" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value; + v2 = value; + v3 = value; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; + + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; + + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; + + offset_custom += 12; + + } + + } else if ( customAttribute.boundTo === "faceVertices" ) { + + for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { + + value = customAttribute.value[ chunk_faces3[ f ] ]; + + v1 = value[ 0 ]; + v2 = value[ 1 ]; + v3 = value[ 2 ]; + + customAttribute.array[ offset_custom ] = v1.x; + customAttribute.array[ offset_custom + 1 ] = v1.y; + customAttribute.array[ offset_custom + 2 ] = v1.z; + customAttribute.array[ offset_custom + 3 ] = v1.w; + + customAttribute.array[ offset_custom + 4 ] = v2.x; + customAttribute.array[ offset_custom + 5 ] = v2.y; + customAttribute.array[ offset_custom + 6 ] = v2.z; + customAttribute.array[ offset_custom + 7 ] = v2.w; + + customAttribute.array[ offset_custom + 8 ] = v3.x; + customAttribute.array[ offset_custom + 9 ] = v3.y; + customAttribute.array[ offset_custom + 10 ] = v3.z; + customAttribute.array[ offset_custom + 11 ] = v3.w; + + offset_custom += 12; + + } + + } + + } + + _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); + + } + + } + + if ( dispose ) { + + delete geometryGroup.__inittedArrays; + delete geometryGroup.__colorArray; + delete geometryGroup.__normalArray; + delete geometryGroup.__tangentArray; + delete geometryGroup.__uvArray; + delete geometryGroup.__uv2Array; + delete geometryGroup.__faceArray; + delete geometryGroup.__vertexArray; + delete geometryGroup.__lineArray; + delete geometryGroup.__skinIndexArray; + delete geometryGroup.__skinWeightArray; + + } + + }; + + // used by renderBufferDirect for THREE.Line + function setupLinesVertexAttributes( material, programAttributes, geometryAttributes, startIndex ) { + + var attributeItem, attributeName, attributePointer, attributeSize; + + for ( attributeName in programAttributes ) { + + attributePointer = programAttributes[ attributeName ]; + attributeItem = geometryAttributes[ attributeName ]; + + if ( attributePointer >= 0 ) { + + if ( attributeItem ) { + + attributeSize = attributeItem.itemSize; + _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); + enableAttribute( attributePointer ); + _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, startIndex * attributeSize * 4 ); // 4 bytes per Float32 + + } else if ( material.defaultAttributeValues ) { + + if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { + + _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + + } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { + + _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + + } + + } + + } + + } + + } + + function setDirectBuffers( geometry, hint ) { + + var attributes = geometry.attributes; + + var attributeName, attributeItem; + + for ( attributeName in attributes ) { + + attributeItem = attributes[ attributeName ]; + + if ( attributeItem.needsUpdate ) { + + if ( attributeName === 'index' ) { + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.buffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.array, hint ); + + } else { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, attributeItem.array, hint ); + + } + + attributeItem.needsUpdate = false; + + } + + } + + } + + // Buffer rendering + + this.renderBufferImmediate = function ( object, program, material ) { + + if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer(); + if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer(); + if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer(); + if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer(); + + if ( object.hasPositions ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); + _gl.enableVertexAttribArray( program.attributes.position ); + _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.hasNormals ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer ); + + if ( material.shading === THREE.FlatShading ) { + + var nx, ny, nz, + nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz, + normalArray, + i, il = object.count * 3; + + for( i = 0; i < il; i += 9 ) { + + normalArray = object.normalArray; + + nax = normalArray[ i ]; + nay = normalArray[ i + 1 ]; + naz = normalArray[ i + 2 ]; + + nbx = normalArray[ i + 3 ]; + nby = normalArray[ i + 4 ]; + nbz = normalArray[ i + 5 ]; + + ncx = normalArray[ i + 6 ]; + ncy = normalArray[ i + 7 ]; + ncz = normalArray[ i + 8 ]; + + nx = ( nax + nbx + ncx ) / 3; + ny = ( nay + nby + ncy ) / 3; + nz = ( naz + nbz + ncz ) / 3; + + normalArray[ i ] = nx; + normalArray[ i + 1 ] = ny; + normalArray[ i + 2 ] = nz; + + normalArray[ i + 3 ] = nx; + normalArray[ i + 4 ] = ny; + normalArray[ i + 5 ] = nz; + + normalArray[ i + 6 ] = nx; + normalArray[ i + 7 ] = ny; + normalArray[ i + 8 ] = nz; + + } + + } + + _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); + _gl.enableVertexAttribArray( program.attributes.normal ); + _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.hasUvs && material.map ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); + _gl.enableVertexAttribArray( program.attributes.uv ); + _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.hasColors && material.vertexColors !== THREE.NoColors ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); + _gl.enableVertexAttribArray( program.attributes.color ); + _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 ); + + } + + _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); + + object.count = 0; + + }; + + this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) { + + if ( material.visible === false ) return; + + var linewidth, a, attribute; + var attributeItem, attributeName, attributePointer, attributeSize; + + var program = setProgram( camera, lights, fog, material, object ); + + var programAttributes = program.attributes; + var geometryAttributes = geometry.attributes; + + var updateBuffers = false, + wireframeBit = material.wireframe ? 1 : 0, + geometryHash = ( geometry.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; + + if ( geometryHash !== _currentGeometryGroupHash ) { + + _currentGeometryGroupHash = geometryHash; + updateBuffers = true; + + } + + if ( updateBuffers ) { + + disableAttributes(); + + } + + // render mesh + + if ( object instanceof THREE.Mesh ) { + + var index = geometryAttributes[ "index" ]; + + // indexed triangles + + if ( index ) { + + var offsets = geometry.offsets; + + // if there is more than 1 chunk + // must set attribute pointers to use new offsets for each chunk + // even if geometry and materials didn't change + + if ( offsets.length > 1 ) updateBuffers = true; + + for ( var i = 0, il = offsets.length; i < il; i ++ ) { + + var startIndex = offsets[ i ].index; + + if ( updateBuffers ) { + + for ( attributeName in programAttributes ) { + + attributePointer = programAttributes[ attributeName ]; + attributeItem = geometryAttributes[ attributeName ]; + + if ( attributePointer >= 0 ) { + + if ( attributeItem ) { + + attributeSize = attributeItem.itemSize; + _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); + enableAttribute( attributePointer ); + _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, startIndex * attributeSize * 4 ); // 4 bytes per Float32 + + } else if ( material.defaultAttributeValues ) { + + if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { + + _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + + } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { + + _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + + } + + } + + } + + } + + // indices + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); + + } + + // render indexed triangles + + _gl.drawElements( _gl.TRIANGLES, offsets[ i ].count, _gl.UNSIGNED_SHORT, offsets[ i ].start * 2 ); // 2 bytes per Uint16 + + _this.info.render.calls ++; + _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared + _this.info.render.faces += offsets[ i ].count / 3; + + } + + // non-indexed triangles + + } else { + + if ( updateBuffers ) { + + for ( attributeName in programAttributes ) { + + if ( attributeName === 'index') continue; + + attributePointer = programAttributes[ attributeName ]; + attributeItem = geometryAttributes[ attributeName ]; + + if ( attributePointer >= 0 ) { + + if ( attributeItem ) { + + attributeSize = attributeItem.itemSize; + _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); + enableAttribute( attributePointer ); + _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 ); + + } else if ( material.defaultAttributeValues && material.defaultAttributeValues[ attributeName ] ) { + + if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { + + _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + + } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { + + _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + + } + + } + + } + + } + + } + + var position = geometry.attributes[ "position" ]; + + // render non-indexed triangles + + _gl.drawArrays( _gl.TRIANGLES, 0, position.array.length / 3 ); + + _this.info.render.calls ++; + _this.info.render.vertices += position.array.length / 3; + _this.info.render.faces += position.array.length / 3 / 3; + + } + + // render particles + + } else if ( object instanceof THREE.ParticleSystem ) { + + if ( updateBuffers ) { + + for ( attributeName in programAttributes ) { + + attributePointer = programAttributes[ attributeName ]; + attributeItem = geometryAttributes[ attributeName ]; + + if ( attributePointer >= 0 ) { + + if ( attributeItem ) { + + attributeSize = attributeItem.itemSize; + _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); + enableAttribute( attributePointer ); + _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 ); + + } else if ( material.defaultAttributeValues && material.defaultAttributeValues[ attributeName ] ) { + + if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { + + _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + + } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { + + _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); + + } + + } + + } + + } + + } + + var position = geometryAttributes[ "position" ]; + + // render particles + + _gl.drawArrays( _gl.POINTS, 0, position.array.length / 3 ); + + _this.info.render.calls ++; + _this.info.render.points += position.array.length / 3; + + } else if ( object instanceof THREE.Line ) { + + var primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; + + setLineWidth( material.linewidth ); + + var index = geometryAttributes[ "index" ]; + + // indexed lines + + if ( index ) { + + var offsets = geometry.offsets; + + // if there is more than 1 chunk + // must set attribute pointers to use new offsets for each chunk + // even if geometry and materials didn't change + + if ( offsets.length > 1 ) updateBuffers = true; + + for ( var i = 0, il = offsets.length; i < il; i ++ ) { + + var startIndex = offsets[ i ].index; + + if ( updateBuffers ) { + + setupLinesVertexAttributes(material, programAttributes, geometryAttributes, startIndex); + + // indices + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); + + } + + // render indexed lines + + _gl.drawElements( _gl.LINES, offsets[ i ].count, _gl.UNSIGNED_SHORT, offsets[ i ].start * 2 ); // 2 bytes per Uint16Array + + _this.info.render.calls ++; + _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared + + } + + } + + // non-indexed lines + + else { + + if ( updateBuffers ) { + + setupLinesVertexAttributes(material, programAttributes, geometryAttributes, 0); + } + + var position = geometryAttributes[ "position" ]; + + _gl.drawArrays( primitives, 0, position.array.length / 3 ); + _this.info.render.calls ++; + _this.info.render.points += position.array.length; + } + + + + } + + }; + + this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) { + + if ( material.visible === false ) return; + + var linewidth, a, attribute, i, il; + + var program = setProgram( camera, lights, fog, material, object ); + + var attributes = program.attributes; + + var updateBuffers = false, + wireframeBit = material.wireframe ? 1 : 0, + geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; + + if ( geometryGroupHash !== _currentGeometryGroupHash ) { + + _currentGeometryGroupHash = geometryGroupHash; + updateBuffers = true; + + } + + if ( updateBuffers ) { + + disableAttributes(); + + } + + // vertices + + if ( !material.morphTargets && attributes.position >= 0 ) { + + if ( updateBuffers ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); + enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + + } + + } else { + + if ( object.morphTargetBase ) { + + setupMorphTargets( material, geometryGroup, object ); + + } + + } + + + if ( updateBuffers ) { + + // custom attributes + + // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers + + if ( geometryGroup.__webglCustomAttributesList ) { + + for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) { + + attribute = geometryGroup.__webglCustomAttributesList[ i ]; + + if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer ); + enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); + _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 ); + + } + + } + + } + + + // colors + + if ( attributes.color >= 0 ) { + + if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); + enableAttribute( attributes.color ); + _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); + + } else if ( material.defaultAttributeValues ) { + + + _gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color ); + + } + + } + + // normals + + if ( attributes.normal >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); + enableAttribute( attributes.normal ); + _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); + + } + + // tangents + + if ( attributes.tangent >= 0 ) { + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); + enableAttribute( attributes.tangent ); + _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); + + } + + // uvs + + if ( attributes.uv >= 0 ) { + + if ( object.geometry.faceVertexUvs[0] ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); + enableAttribute( attributes.uv ); + _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); + + } else if ( material.defaultAttributeValues ) { + + + _gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv ); + + } + + } + + if ( attributes.uv2 >= 0 ) { + + if ( object.geometry.faceVertexUvs[1] ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); + enableAttribute( attributes.uv2 ); + _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 ); + + } else if ( material.defaultAttributeValues ) { + + + _gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 ); + + } + + } + + if ( material.skinning && + attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); + enableAttribute( attributes.skinIndex ); + _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 ); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); + enableAttribute( attributes.skinWeight ); + _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 ); + + } + + // line distances + + if ( attributes.lineDistance >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer ); + enableAttribute( attributes.lineDistance ); + _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 ); + + } + + } + + // render mesh + + if ( object instanceof THREE.Mesh ) { + + // wireframe + + if ( material.wireframe ) { + + setLineWidth( material.wireframeLinewidth ); + + if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); + _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, _gl.UNSIGNED_SHORT, 0 ); + + // triangles + + } else { + + if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); + _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, _gl.UNSIGNED_SHORT, 0 ); + + } + + _this.info.render.calls ++; + _this.info.render.vertices += geometryGroup.__webglFaceCount; + _this.info.render.faces += geometryGroup.__webglFaceCount / 3; + + // render lines + + } else if ( object instanceof THREE.Line ) { + + var primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; + + setLineWidth( material.linewidth ); + + _gl.drawArrays( primitives, 0, geometryGroup.__webglLineCount ); + + _this.info.render.calls ++; + + // render particles + + } else if ( object instanceof THREE.ParticleSystem ) { + + _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount ); + + _this.info.render.calls ++; + _this.info.render.points += geometryGroup.__webglParticleCount; + + } + + }; + + function enableAttribute( attribute ) { + + if ( _enabledAttributes[ attribute ] === 0 ) { + + _gl.enableVertexAttribArray( attribute ); + _enabledAttributes[ attribute ] = 1; + + } + + }; + + function disableAttributes() { + + for ( var attribute in _enabledAttributes ) { + + if ( _enabledAttributes[ attribute ] === 1 ) { + + _gl.disableVertexAttribArray( attribute ); + _enabledAttributes[ attribute ] = 0; + + } + + } + + }; + + function setupMorphTargets ( material, geometryGroup, object ) { + + // set base + + var attributes = material.program.attributes; + + if ( object.morphTargetBase !== -1 && attributes.position >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] ); + enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + + } else if ( attributes.position >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); + enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( object.morphTargetForcedOrder.length ) { + + // set forced order + + var m = 0; + var order = object.morphTargetForcedOrder; + var influences = object.morphTargetInfluences; + + while ( m < material.numSupportedMorphTargets && m < order.length ) { + + if ( attributes[ "morphTarget" + m ] >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] ); + enableAttribute( attributes[ "morphTarget" + m ] ); + _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] ); + enableAttribute( attributes[ "morphNormal" + m ] ); + _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + } + + object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ]; + + m ++; + } + + } else { + + // find the most influencing + + var influence, activeInfluenceIndices = []; + var influences = object.morphTargetInfluences; + var i, il = influences.length; + + for ( i = 0; i < il; i ++ ) { + + influence = influences[ i ]; + + if ( influence > 0 ) { + + activeInfluenceIndices.push( [ influence, i ] ); + + } + + } + + if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) { + + activeInfluenceIndices.sort( numericalSort ); + activeInfluenceIndices.length = material.numSupportedMorphTargets; + + } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) { + + activeInfluenceIndices.sort( numericalSort ); + + } else if ( activeInfluenceIndices.length === 0 ) { + + activeInfluenceIndices.push( [ 0, 0 ] ); + + }; + + var influenceIndex, m = 0; + + while ( m < material.numSupportedMorphTargets ) { + + if ( activeInfluenceIndices[ m ] ) { + + influenceIndex = activeInfluenceIndices[ m ][ 1 ]; + + if ( attributes[ "morphTarget" + m ] >= 0 ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] ); + enableAttribute( attributes[ "morphTarget" + m ] ); + _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + } + + if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { + + _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] ); + enableAttribute( attributes[ "morphNormal" + m ] ); + _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + + } + + object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ]; + + } else { + + /* + _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + if ( material.morphNormals ) { + + _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); + + } + */ + + object.__webglMorphTargetInfluences[ m ] = 0; + + } + + m ++; + + } + + } + + // load updated influences uniform + + if ( material.program.uniforms.morphTargetInfluences !== null ) { + + _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences ); + + } + + }; + + // Sorting + + function painterSortStable ( a, b ) { + + if ( a.z !== b.z ) { + + return b.z - a.z; + + } else { + + return a.id - b.id; + + } + + }; + + function numericalSort ( a, b ) { + + return b[ 0 ] - a[ 0 ]; + + }; + + + // Rendering + + this.render = function ( scene, camera, renderTarget, forceClear ) { + + if ( camera instanceof THREE.Camera === false ) { + + THREE.onerror( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + return; + + } + + var i, il, + + webglObject, object, + renderList, + + lights = scene.__lights, + fog = scene.fog; + + // reset caching for this frame + + _currentMaterialId = -1; + _lightsNeedUpdate = true; + + // update scene graph + + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + + // update camera matrices and frustum + + if ( camera.parent === undefined ) camera.updateMatrixWorld(); + + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); + + // update WebGL objects + + if ( this.autoUpdateObjects ) this.initWebGLObjects( scene ); + + // custom render plugins (pre pass) + + renderPlugins( this.renderPluginsPre, scene, camera ); + + // + + _this.info.render.calls = 0; + _this.info.render.vertices = 0; + _this.info.render.faces = 0; + _this.info.render.points = 0; + + this.setRenderTarget( renderTarget ); + + if ( this.autoClear || forceClear ) { + + this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); + + } + + // set matrices for regular objects (frustum culled) + + renderList = scene.__webglObjects; + + for ( i = 0, il = renderList.length; i < il; i ++ ) { + + webglObject = renderList[ i ]; + object = webglObject.object; + + webglObject.id = i; + webglObject.render = false; + + if ( object.visible ) { + + if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { + + setupMatrices( object, camera ); + + unrollBufferMaterial( webglObject ); + + webglObject.render = true; + + if ( this.sortObjects === true ) { + + if ( object.renderDepth !== null ) { + + webglObject.z = object.renderDepth; + + } else { + + _vector3.setFromMatrixPosition( object.matrixWorld ); + _vector3.applyProjection( _projScreenMatrix ); + + webglObject.z = _vector3.z; + + } + + } + + } + + } + + } + + if ( this.sortObjects ) { + + renderList.sort( painterSortStable ); + + } + + // set matrices for immediate objects + + renderList = scene.__webglObjectsImmediate; + + for ( i = 0, il = renderList.length; i < il; i ++ ) { + + webglObject = renderList[ i ]; + object = webglObject.object; + + if ( object.visible ) { + + setupMatrices( object, camera ); + + unrollImmediateBufferMaterial( webglObject ); + + } + + } + + if ( scene.overrideMaterial ) { + + var material = scene.overrideMaterial; + + this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + this.setDepthTest( material.depthTest ); + this.setDepthWrite( material.depthWrite ); + setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + + renderObjects( scene.__webglObjects, false, "", camera, lights, fog, true, material ); + renderObjectsImmediate( scene.__webglObjectsImmediate, "", camera, lights, fog, false, material ); + + } else { + + var material = null; + + // opaque pass (front-to-back order) + + this.setBlending( THREE.NoBlending ); + + renderObjects( scene.__webglObjects, true, "opaque", camera, lights, fog, false, material ); + renderObjectsImmediate( scene.__webglObjectsImmediate, "opaque", camera, lights, fog, false, material ); + + // transparent pass (back-to-front order) + + renderObjects( scene.__webglObjects, false, "transparent", camera, lights, fog, true, material ); + renderObjectsImmediate( scene.__webglObjectsImmediate, "transparent", camera, lights, fog, true, material ); + + } + + // custom render plugins (post pass) + + renderPlugins( this.renderPluginsPost, scene, camera ); + + + // Generate mipmap if we're using any kind of mipmap filtering + + if ( renderTarget && renderTarget.generateMipmaps && + renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter && + THREE.isPowerOfTwo( renderTarget.width ) && THREE.isPowerOfTwo( renderTarget.height ) ) { + + updateRenderTargetMipmap( renderTarget ); + + } + + // Ensure depth buffer writing is enabled so it can be cleared on next render + + this.setDepthTest( true ); + this.setDepthWrite( true ); + + // _gl.finish(); + + }; + + function renderPlugins( plugins, scene, camera ) { + + if ( ! plugins.length ) return; + + for ( var i = 0, il = plugins.length; i < il; i ++ ) { + + // reset state for plugin (to start from clean slate) + + _currentProgram = null; + _currentCamera = null; + + _oldBlending = -1; + _oldDepthTest = -1; + _oldDepthWrite = -1; + _oldDoubleSided = -1; + _oldFlipSided = -1; + _currentGeometryGroupHash = -1; + _currentMaterialId = -1; + + _lightsNeedUpdate = true; + + plugins[ i ].render( scene, camera, _currentWidth, _currentHeight ); + + // reset state after plugin (anything could have changed) + + _currentProgram = null; + _currentCamera = null; + + _oldBlending = -1; + _oldDepthTest = -1; + _oldDepthWrite = -1; + _oldDoubleSided = -1; + _oldFlipSided = -1; + _currentGeometryGroupHash = -1; + _currentMaterialId = -1; + + _lightsNeedUpdate = true; + + } + + }; + + function renderObjects( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) { + + var webglObject, object, buffer, material, start, end, delta; + + if ( reverse ) { + + start = renderList.length - 1; + end = -1; + delta = -1; + + } else { + + start = 0; + end = renderList.length; + delta = 1; + } + + for ( var i = start; i !== end; i += delta ) { + + webglObject = renderList[ i ]; + + if ( webglObject.render ) { + + object = webglObject.object; + buffer = webglObject.buffer; + + if ( overrideMaterial ) { + + material = overrideMaterial; + + } else { + + material = webglObject[ materialType ]; + + if ( ! material ) continue; + + if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + + _this.setDepthTest( material.depthTest ); + _this.setDepthWrite( material.depthWrite ); + setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + + } + + _this.setMaterialFaces( material ); + + if ( buffer instanceof THREE.BufferGeometry ) { + + _this.renderBufferDirect( camera, lights, fog, material, buffer, object ); + + } else { + + _this.renderBuffer( camera, lights, fog, material, buffer, object ); + + } + + } + + } + + }; + + function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) { + + var webglObject, object, material, program; + + for ( var i = 0, il = renderList.length; i < il; i ++ ) { + + webglObject = renderList[ i ]; + object = webglObject.object; + + if ( object.visible ) { + + if ( overrideMaterial ) { + + material = overrideMaterial; + + } else { + + material = webglObject[ materialType ]; + + if ( ! material ) continue; + + if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + + _this.setDepthTest( material.depthTest ); + _this.setDepthWrite( material.depthWrite ); + setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + + } + + _this.renderImmediateObject( camera, lights, fog, material, object ); + + } + + } + + }; + + this.renderImmediateObject = function ( camera, lights, fog, material, object ) { + + var program = setProgram( camera, lights, fog, material, object ); + + _currentGeometryGroupHash = -1; + + _this.setMaterialFaces( material ); + + if ( object.immediateRenderCallback ) { + + object.immediateRenderCallback( program, _gl, _frustum ); + + } else { + + object.render( function( object ) { _this.renderBufferImmediate( object, program, material ); } ); + + } + + }; + + function unrollImmediateBufferMaterial ( globject ) { + + var object = globject.object, + material = object.material; + + if ( material.transparent ) { + + globject.transparent = material; + globject.opaque = null; + + } else { + + globject.opaque = material; + globject.transparent = null; + + } + + }; + + function unrollBufferMaterial ( globject ) { + + var object = globject.object; + var buffer = globject.buffer; + + var geometry = object.geometry; + var material = object.material; + + if ( material instanceof THREE.MeshFaceMaterial ) { + + var materialIndex = geometry instanceof THREE.BufferGeometry ? 0 : buffer.materialIndex; + + material = material.materials[ materialIndex ]; + + if ( material.transparent ) { + + globject.transparent = material; + globject.opaque = null; + + } else { + + globject.opaque = material; + globject.transparent = null; + + } + + } else { + + if ( material ) { + + if ( material.transparent ) { + + globject.transparent = material; + globject.opaque = null; + + } else { + + globject.opaque = material; + globject.transparent = null; + + } + + } + + } + + }; + + // Objects refresh + + this.initWebGLObjects = function ( scene ) { + + if ( !scene.__webglObjects ) { + + scene.__webglObjects = []; + scene.__webglObjectsImmediate = []; + scene.__webglSprites = []; + scene.__webglFlares = []; + + } + + while ( scene.__objectsAdded.length ) { + + addObject( scene.__objectsAdded[ 0 ], scene ); + scene.__objectsAdded.splice( 0, 1 ); + + } + + while ( scene.__objectsRemoved.length ) { + + removeObject( scene.__objectsRemoved[ 0 ], scene ); + scene.__objectsRemoved.splice( 0, 1 ); + + } + + // update must be called after objects adding / removal + + for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) { + + var object = scene.__webglObjects[ o ].object; + + // TODO: Remove this hack (WebGLRenderer refactoring) + + if ( object.__webglInit === undefined ) { + + if ( object.__webglActive !== undefined ) { + + removeObject( object, scene ); + + } + + addObject( object, scene ); + + } + + updateObject( object ); + + } + + }; + + // Objects adding + + function addObject( object, scene ) { + + var g, geometry, material, geometryGroup; + + if ( object.__webglInit === undefined ) { + + object.__webglInit = true; + + object._modelViewMatrix = new THREE.Matrix4(); + object._normalMatrix = new THREE.Matrix3(); + + if ( object.geometry !== undefined && object.geometry.__webglInit === undefined ) { + + object.geometry.__webglInit = true; + object.geometry.addEventListener( 'dispose', onGeometryDispose ); + + } + + geometry = object.geometry; + + if ( geometry === undefined ) { + + // fail silently for now + + } else if ( geometry instanceof THREE.BufferGeometry ) { + + initDirectBuffers( geometry ); + + } else if ( object instanceof THREE.Mesh ) { + + material = object.material; + + if ( geometry.geometryGroups === undefined ) { + + geometry.makeGroups( material instanceof THREE.MeshFaceMaterial ); + + } + + // create separate VBOs per geometry chunk + + for ( g in geometry.geometryGroups ) { + + geometryGroup = geometry.geometryGroups[ g ]; + + // initialise VBO on the first access + + if ( ! geometryGroup.__webglVertexBuffer ) { + + createMeshBuffers( geometryGroup ); + initMeshBuffers( geometryGroup, object ); + + geometry.verticesNeedUpdate = true; + geometry.morphTargetsNeedUpdate = true; + geometry.elementsNeedUpdate = true; + geometry.uvsNeedUpdate = true; + geometry.normalsNeedUpdate = true; + geometry.tangentsNeedUpdate = true; + + geometry.colorsNeedUpdate = true; + + } + + } + + } else if ( object instanceof THREE.Line ) { + + if ( ! geometry.__webglVertexBuffer ) { + + createLineBuffers( geometry ); + initLineBuffers( geometry, object ); + + geometry.verticesNeedUpdate = true; + geometry.colorsNeedUpdate = true; + geometry.lineDistancesNeedUpdate = true; + + } + + } else if ( object instanceof THREE.ParticleSystem ) { + + if ( ! geometry.__webglVertexBuffer ) { + + createParticleBuffers( geometry ); + initParticleBuffers( geometry, object ); + + geometry.verticesNeedUpdate = true; + geometry.colorsNeedUpdate = true; + + } + + } + + } + + if ( object.__webglActive === undefined ) { + + if ( object instanceof THREE.Mesh ) { + + geometry = object.geometry; + + if ( geometry instanceof THREE.BufferGeometry ) { + + addBuffer( scene.__webglObjects, geometry, object ); + + } else if ( geometry instanceof THREE.Geometry ) { + + for ( g in geometry.geometryGroups ) { + + geometryGroup = geometry.geometryGroups[ g ]; + + addBuffer( scene.__webglObjects, geometryGroup, object ); + + } + + } + + } else if ( object instanceof THREE.Line || + object instanceof THREE.ParticleSystem ) { + + geometry = object.geometry; + addBuffer( scene.__webglObjects, geometry, object ); + + } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { + + addBufferImmediate( scene.__webglObjectsImmediate, object ); + + } else if ( object instanceof THREE.Sprite ) { + + scene.__webglSprites.push( object ); + + } else if ( object instanceof THREE.LensFlare ) { + + scene.__webglFlares.push( object ); + + } + + object.__webglActive = true; + + } + + }; + + function addBuffer( objlist, buffer, object ) { + + objlist.push( + { + id: null, + buffer: buffer, + object: object, + opaque: null, + transparent: null, + z: 0 + } + ); + + }; + + function addBufferImmediate( objlist, object ) { + + objlist.push( + { + id: null, + object: object, + opaque: null, + transparent: null, + z: 0 + } + ); + + }; + + // Objects updates + + function updateObject( object ) { + + var geometry = object.geometry, + geometryGroup, customAttributesDirty, material; + + if ( geometry instanceof THREE.BufferGeometry ) { + + setDirectBuffers( geometry, _gl.DYNAMIC_DRAW ); + + } else if ( object instanceof THREE.Mesh ) { + + // check all geometry groups + + for( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) { + + geometryGroup = geometry.geometryGroupsList[ i ]; + + material = getBufferMaterial( object, geometryGroup ); + + if ( geometry.buffersNeedUpdate ) { + + initMeshBuffers( geometryGroup, object ); + + } + + customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + + if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate || + geometry.uvsNeedUpdate || geometry.normalsNeedUpdate || + geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) { + + setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, !geometry.dynamic, material ); + + } + + } + + geometry.verticesNeedUpdate = false; + geometry.morphTargetsNeedUpdate = false; + geometry.elementsNeedUpdate = false; + geometry.uvsNeedUpdate = false; + geometry.normalsNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.tangentsNeedUpdate = false; + + geometry.buffersNeedUpdate = false; + + material.attributes && clearCustomAttributes( material ); + + } else if ( object instanceof THREE.Line ) { + + material = getBufferMaterial( object, geometry ); + + customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + + if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) { + + setLineBuffers( geometry, _gl.DYNAMIC_DRAW ); + + } + + geometry.verticesNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.lineDistancesNeedUpdate = false; + + material.attributes && clearCustomAttributes( material ); + + + } else if ( object instanceof THREE.ParticleSystem ) { + + material = getBufferMaterial( object, geometry ); + + customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); + + if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || object.sortParticles || customAttributesDirty ) { + + setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object ); + + } + + geometry.verticesNeedUpdate = false; + geometry.colorsNeedUpdate = false; + + material.attributes && clearCustomAttributes( material ); + + } + + }; + + // Objects updates - custom attributes check + + function areCustomAttributesDirty( material ) { + + for ( var a in material.attributes ) { + + if ( material.attributes[ a ].needsUpdate ) return true; + + } + + return false; + + }; + + function clearCustomAttributes( material ) { + + for ( var a in material.attributes ) { + + material.attributes[ a ].needsUpdate = false; + + } + + }; + + // Objects removal + + function removeObject( object, scene ) { + + if ( object instanceof THREE.Mesh || + object instanceof THREE.ParticleSystem || + object instanceof THREE.Line ) { + + removeInstances( scene.__webglObjects, object ); + + } else if ( object instanceof THREE.Sprite ) { + + removeInstancesDirect( scene.__webglSprites, object ); + + } else if ( object instanceof THREE.LensFlare ) { + + removeInstancesDirect( scene.__webglFlares, object ); + + } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { + + removeInstances( scene.__webglObjectsImmediate, object ); + + } + + delete object.__webglActive; + + }; + + function removeInstances( objlist, object ) { + + for ( var o = objlist.length - 1; o >= 0; o -- ) { + + if ( objlist[ o ].object === object ) { + + objlist.splice( o, 1 ); + + } + + } + + }; + + function removeInstancesDirect( objlist, object ) { + + for ( var o = objlist.length - 1; o >= 0; o -- ) { + + if ( objlist[ o ] === object ) { + + objlist.splice( o, 1 ); + + } + + } + + }; + + // Materials + + this.initMaterial = function ( material, lights, fog, object ) { + + material.addEventListener( 'dispose', onMaterialDispose ); + + var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID; + + if ( material instanceof THREE.MeshDepthMaterial ) { + + shaderID = 'depth'; + + } else if ( material instanceof THREE.MeshNormalMaterial ) { + + shaderID = 'normal'; + + } else if ( material instanceof THREE.MeshBasicMaterial ) { + + shaderID = 'basic'; + + } else if ( material instanceof THREE.MeshLambertMaterial ) { + + shaderID = 'lambert'; + + } else if ( material instanceof THREE.MeshPhongMaterial ) { + + shaderID = 'phong'; + + } else if ( material instanceof THREE.MeshPhysicalMaterial ) { + + shaderID = 'physical'; + + } else if ( material instanceof THREE.LineBasicMaterial ) { + + shaderID = 'basic'; + + } else if ( material instanceof THREE.LineDashedMaterial ) { + + shaderID = 'dashed'; + + } else if ( material instanceof THREE.ParticleSystemMaterial ) { + + shaderID = 'particle_basic'; + + } + + if ( shaderID && THREE.ShaderLib[ shaderID ] ) { + + setMaterialShaders( material, THREE.ShaderLib[ shaderID ] ); + + } + + if( ! shaderID ) { + shaderID = material.shaderID; + } + + // heuristics to create shader parameters according to lights in the scene + // (not to blow over maxLights budget) + + maxLightCount = allocateLights( lights ); + + maxShadows = allocateShadows( lights ); + + maxBones = allocateBones( object ); + + parameters = { + + map: !!material.map, + opacityMap: !!material.opacityMap, + envMap: !!material.envMap, + diffuseEnvMap: !!material.diffuseEnvMap, + lightMap: !!material.lightMap, + emissiveMap: !!material.emissiveMap, + bumpMap: !!material.bumpMap, + normalMap: !!material.normalMap, + specularMap: !!material.specularMap, + reflectivityMap: !!material.reflectivityMap, + roughnessMap: !!material.roughnessMap, + translucencyMap: !!material.translucencyMap, + metallicMap: !!material.metallicMap, + falloffMap: !!material.falloffMap, + + clearCoat: (( material.clearCoat !== undefined )&&( material.clearCoat !== 0 )), + + anisotropy: (( material.anisotropy !== undefined )&&( material.anisotropy !== 0 ))||( !! material.anisotropyMap ), + anisotropyMap: !! material.anisotropyMap, + anisotropyRotation: (( material.anisotropyRotation !== undefined )&&( material.anisotropyRotation !== 0 ))||( !! material.anisotropyRotationMap ), + anisotropyRotationMap: !! material.anisotropyRotationMap, + + vertexColors: material.vertexColors, + + fog: fog, + useFog: material.fog, + fogExp: fog instanceof THREE.FogExp2, + + sizeAttenuation: !! material.sizeAttenuation, + + skinning: material.skinning, + maxBones: maxBones, + useVertexTexture: _supportsBoneTextures && object && object.useVertexTexture, + + morphTargets: material.morphTargets, + morphNormals: material.morphNormals, + maxMorphTargets: this.maxMorphTargets, + maxMorphNormals: this.maxMorphNormals, + + maxDirLights: maxLightCount.directional, + maxPointLights: maxLightCount.point, + maxSpotLights: maxLightCount.spot, + maxHemiLights: maxLightCount.hemi, + maxAreaLights: maxLightCount.area, + + maxShadows: maxShadows, + shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow && maxShadows > 0, + shadowMapType: this.shadowMapType, + shadowMapDebug: this.shadowMapDebug, + shadowMapCascade: this.shadowMapCascade, + + translucency: material.translucency && ( material.translucency.getHex() > 0 ), + + alphaTest: material.alphaTest, + falloff: ( material.falloff || false ), + wrapAround: material.wrapAround, + doubleSided: material.side === THREE.DoubleSide, + flipSided: material.side === THREE.BackSide + + }; + + material.program = buildProgram( shaderID, material.fragmentShader, material.vertexShader, material.uniforms, material.attributes, material.defines, parameters, material.index0AttributeName ); + + var attributes = material.program.attributes; + + if ( material.morphTargets ) { + + material.numSupportedMorphTargets = 0; + + var id, base = "morphTarget"; + + for ( i = 0; i < this.maxMorphTargets; i ++ ) { + + id = base + i; + + if ( attributes[ id ] >= 0 ) { + + material.numSupportedMorphTargets ++; + + } + + } + + } + + if ( material.morphNormals ) { + + material.numSupportedMorphNormals = 0; + + var id, base = "morphNormal"; + + for ( i = 0; i < this.maxMorphNormals; i ++ ) { + + id = base + i; + + if ( attributes[ id ] >= 0 ) { + + material.numSupportedMorphNormals ++; + + } + + } + + } + + material.uniformsList = []; + + for ( u in material.uniforms ) { + + material.uniformsList.push( [ material.uniforms[ u ], u ] ); + + } + + }; + + function setMaterialShaders( material, shaders ) { + + material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms ); + material.vertexShader = shaders.vertexShader; + material.fragmentShader = shaders.fragmentShader; + + }; + + function setProgram( camera, lights, fog, material, object ) { + + _usedTextureUnits = 0; + + if ( material.needsUpdate ) { + + var oldProgram = material.program; + + _this.initMaterial( material, lights, fog, object ); + material.needsUpdate = false; + + if ( oldProgram ) deallocateMaterial( material, oldProgram ); + + + } + + if ( material.morphTargets ) { + + if ( ! object.__webglMorphTargetInfluences ) { + + object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets ); + + } + + } + + var refreshMaterial = false; + + var program = material.program, + p_uniforms = program.uniforms, + m_uniforms = material.uniforms; + + if ( program !== _currentProgram ) { + + _gl.useProgram( program ); + _currentProgram = program; + + refreshMaterial = true; + + } + + if ( material.id !== _currentMaterialId ) { + + _currentMaterialId = material.id; + refreshMaterial = true; + + } + + if ( refreshMaterial || camera !== _currentCamera ) { + + _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); + + if ( camera !== _currentCamera ) _currentCamera = camera; + + } + + // skinning uniforms must be set even if material didn't change + // auto-setting of texture unit for bone texture must go before other textures + // not sure why, but otherwise weird things happen + + if ( material.skinning ) { + + if ( _supportsBoneTextures && object.useVertexTexture ) { + + if ( p_uniforms.boneTexture !== null ) { + + var textureUnit = getTextureUnit(); + + _gl.uniform1i( p_uniforms.boneTexture, textureUnit ); + _this.setTexture( object.boneTexture, textureUnit ); + + } + + if ( p_uniforms.boneTextureWidth !== null ) { + + _gl.uniform1i( p_uniforms.boneTextureWidth, object.boneTextureWidth ); + + } + + if ( p_uniforms.boneTextureHeight !== null ) { + + _gl.uniform1i( p_uniforms.boneTextureHeight, object.boneTextureHeight ); + + } + + } else { + + if ( p_uniforms.boneGlobalMatrices !== null ) { + + _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices ); + + } + + } + + } + + if ( refreshMaterial ) { + + // refresh uniforms common to several materials + + if ( fog && material.fog ) { + + refreshUniformsFog( m_uniforms, fog ); + + } + + if ( material instanceof THREE.MeshPhongMaterial || + material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshPhysicalMaterial || + material.lights ) { + + if ( _lightsNeedUpdate ) { + + setupLights( program, lights ); + _lightsNeedUpdate = false; + + } + + refreshUniformsLights( m_uniforms, _lights ); + + } + + if ( material instanceof THREE.MeshBasicMaterial || + material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshPhysicalMaterial || + material instanceof THREE.MeshPhongMaterial ) { + + refreshUniformsCommon( m_uniforms, material ); + + } + + // refresh single material specific uniforms + + if ( material instanceof THREE.LineBasicMaterial ) { + + refreshUniformsLine( m_uniforms, material ); + + } else if ( material instanceof THREE.LineDashedMaterial ) { + + refreshUniformsLine( m_uniforms, material ); + refreshUniformsDash( m_uniforms, material ); + + } else if ( material instanceof THREE.ParticleSystemMaterial ) { + + refreshUniformsParticle( m_uniforms, material ); + + } else if ( material instanceof THREE.MeshPhongMaterial ) { + + refreshUniformsPhong( m_uniforms, material ); + + } else if ( material instanceof THREE.MeshPhysicalMaterial ) { + + refreshUniformsPhysical( m_uniforms, material ); + + } else if ( material instanceof THREE.MeshLambertMaterial ) { + + refreshUniformsLambert( m_uniforms, material ); + + } else if ( material instanceof THREE.MeshDepthMaterial ) { + + m_uniforms.mNear.value = camera.near; + m_uniforms.mFar.value = camera.far; + m_uniforms.opacity.value = material.opacity; + + } else if ( material instanceof THREE.MeshNormalMaterial ) { + + m_uniforms.opacity.value = material.opacity; + + } + + if ( object.receiveShadow && ! material._shadowPass ) { + + refreshUniformsShadow( m_uniforms, lights ); + + } + + // load common uniforms + + loadUniformsGeneric( program, material.uniformsList ); + + // load material specific uniforms + // (shader material also gets them for the sake of genericity) + + if ( material instanceof THREE.ShaderMaterial || + material instanceof THREE.MeshPhongMaterial || + material instanceof THREE.MeshPhysicalMaterial || + material.envMap || + material.diffuseEnvMap ) { + + if ( p_uniforms.cameraPosition !== null ) { + + _vector3.setFromMatrixPosition( camera.matrixWorld ); + _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z ); + + } + + } + + if ( material instanceof THREE.MeshPhongMaterial || + material instanceof THREE.MeshLambertMaterial || + material instanceof THREE.MeshPhysicalMaterial || + material instanceof THREE.ShaderMaterial || + material.skinning ) { + + if ( p_uniforms.viewMatrix !== null ) { + + _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements ); + + } + + } + + } + + loadUniformsMatrices( p_uniforms, object ); + + if ( p_uniforms.modelMatrix !== null ) { + + _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements ); + + } + + return program; + + }; + + // Uniforms (refresh uniforms objects) + + function refreshUniformsCommon ( uniforms, material ) { + + uniforms.opacity.value = material.opacity; + + uniforms.diffuse.value = material.color; + + uniforms.map.value = material.map; + uniforms.lightMap.value = material.lightMap; + uniforms.emissiveMap.value = material.emissiveMap; + + if ( material.bumpMap ) { + + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; + + } + + if ( material.normalMap ) { + + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); + + } + + if ( material.map ) { + + var map = material.map; + uniforms.offsetRepeat.value.set( map.offset.x, map.offset.y, map.repeat.x, map.repeat.y ); + uniforms.gainBrightness.value.set( map.gainPivot, map.gain, map.brightness, map.invert ? -1.0 : 1.0 ); + + } + + if ( material.specularMap ) { + + var specularMap = material.specularMap; + uniforms.specularMap.value = specularMap; + uniforms.specularOffsetRepeat.value.set( specularMap.offset.x, specularMap.offset.y, specularMap.repeat.x, specularMap.repeat.y ); + uniforms.specularGainBrightness.value.set( specularMap.gainPivot, specularMap.gain, specularMap.brightness, specularMap.invert ? -1.0 : 1.0 ); + + } + + if ( material.opacityMap ) { + + var opacityMap = material.opacityMap; + uniforms.opacityMap.value = opacityMap; + uniforms.opacityOffsetRepeat.value.set( opacityMap.offset.x, opacityMap.offset.y, opacityMap.repeat.x, opacityMap.repeat.y ); + uniforms.opacityGainBrightness.value.set( opacityMap.gainPivot, opacityMap.gain, opacityMap.brightness, opacityMap.invert ? -1.0 : 1.0 ); + + } + + if ( material.bumpMap ) { + + var bumpMap = material.bumpMap; + uniforms.bumpOffsetRepeat.value.set( bumpMap.offset.x, bumpMap.offset.y, bumpMap.repeat.x, bumpMap.repeat.y ); + //uniforms.bumpGainBrightness.value.set( bumpMap.gainPivot, bumpMap.gain, bumpMap.brightness, 1.0 ); + + } + + if ( material.normalMap ) { + + var normalMap = material.normalMap; + uniforms.normalOffsetRepeat.value.set( normalMap.offset.x, normalMap.offset.y, normalMap.repeat.x, normalMap.repeat.y ); + //uniforms.normalGainBrightness.value.set( normalMap.gainPivot, normalMap.gain, normalMap.brightness, 1.0 ); + + } + + if ( material.anisotropyMap ) { + + var anisotropyMap = material.anisotropyMap; + uniforms.anisotropyOffsetRepeat.value.set( anisotropyMap.offset.x, anisotropyMap.offset.y, anisotropyMap.repeat.x, anisotropyMap.repeat.y ); + uniforms.anisotropyGainBrightness.value.set( anisotropyMap.gainPivot, anisotropyMap.gain, anisotropyMap.brightness, anisotropyMap.invert ? -1.0 : 1.0 ); + + } + + if ( material.anisotropyRotationMap ) { + + var anisotropyRotationMap = material.anisotropyRotationMap; + uniforms.anisotropyRotationOffsetRepeat.value.set( anisotropyRotationMap.offset.x, anisotropyRotationMap.offset.y, anisotropyRotationMap.repeat.x, anisotropyRotationMap.repeat.y ); + uniforms.anisotropyRotationGainBrightness.value.set( anisotropyRotationMap.gainPivot, anisotropyRotationMap.gain, anisotropyRotationMap.brightness, anisotropyRotationMap.invert ? -1.0 : 1.0 ); + + } + + if ( material.roughnessMap ) { + + var roughnessMap = material.roughnessMap; + uniforms.roughnessOffsetRepeat.value.set( roughnessMap.offset.x, roughnessMap.offset.y, roughnessMap.repeat.x, roughnessMap.repeat.y ); + uniforms.roughnessGainBrightness.value.set( roughnessMap.gainPivot, roughnessMap.gain, roughnessMap.brightness, roughnessMap.invert ? -1.0 : 1.0 ); + + } + + if ( material.metallicMap ) { + + var metallicMap = material.metallicMap; + uniforms.metallicOffsetRepeat.value.set( metallicMap.offset.x, metallicMap.offset.y, metallicMap.repeat.x, metallicMap.repeat.y ); + uniforms.metallicGainBrightness.value.set( metallicMap.gainPivot, metallicMap.gain, metallicMap.brightness, metallicMap.invert ? -1.0 : 1.0 ); + + } + + if ( material.translucencyMap ) { + + var translucencyMap = material.translucencyMap; + uniforms.translucencyMap.value = translucencyMap; + //uniforms.translucencyOffsetRepeat.value.set( translucencyMap.offset.x, translucencyMap.offset.y, translucencyMap.repeat.x, translucencyMap.repeat.y ); + //uniforms.translucencyGainBrightness.value.set( translucencyMap.gainPivot, translucencyMap.gain, translucencyMap.brightness, 1.0 ); + + } + uniforms.envMap.value = material.envMap; + uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1; + uniforms.envEncoding.value = ( material.envMap ) ? material.envMap.encoding : 0; + uniforms.diffuseEnvMap.value = material.diffuseEnvMap; + uniforms.diffuseEnvEncoding.value = ( material.diffuseEnvMap ) ? material.diffuseEnvMap.encoding : 0; + + uniforms.reflectivity.value = material.reflectivity; + + uniforms.refractionRatio.value = material.refractionRatio; + uniforms.combine.value = material.combine; + uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping; + + }; + + function refreshUniformsLine ( uniforms, material ) { + + uniforms.diffuse.value = material.color; + uniforms.opacity.value = material.opacity; + + }; + + function refreshUniformsDash ( uniforms, material ) { + + uniforms.dashSize.value = material.dashSize; + uniforms.totalSize.value = material.dashSize + material.gapSize; + uniforms.scale.value = material.scale; + + }; + + function refreshUniformsParticle ( uniforms, material ) { + + uniforms.psColor.value = material.color; + uniforms.opacity.value = material.opacity; + uniforms.size.value = material.size; + uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this. + + uniforms.map.value = material.map; + + }; + + function refreshUniformsFog ( uniforms, fog ) { + + uniforms.fogColor.value = fog.color; + + if ( fog instanceof THREE.Fog ) { + + uniforms.fogNear.value = fog.near; + uniforms.fogFar.value = fog.far; + + } else if ( fog instanceof THREE.FogExp2 ) { + + uniforms.fogDensity.value = fog.density; + + } + + }; + + function refreshUniformsPhong ( uniforms, material ) { + + uniforms.opacityMap.value = material.opacityMap; + + uniforms.shininess.value = material.shininess; + + uniforms.ambient.value = material.ambient; + uniforms.emissive.value = material.emissive; + uniforms.specular.value = material.specular; + + if ( material.wrapAround ) { + + uniforms.wrapRGB.value.copy( material.wrapRGB ); + + } + + }; + + function refreshUniformsPhysical ( uniforms, material ) { + + uniforms.opacityMap.value = material.opacityMap; + + uniforms.falloffBlendParams.value = material.falloffBlendParams; + uniforms.falloffMap.value = material.falloffMap; + + uniforms.roughness.value = material.roughness; + uniforms.metallic.value = material.metallic; + + uniforms.clearCoat.value = material.clearCoat; + uniforms.clearCoatRoughness.value = material.clearCoatRoughness; + + uniforms.roughnessMap.value = material.roughnessMap; + uniforms.metallicMap.value = material.metallicMap; + + uniforms.translucencyMap.value = material.translucencyMap; + uniforms.translucencyNormalAlpha.value = material.translucencyNormalAlpha; + uniforms.translucencyNormalPower.value = material.translucencyNormalPower; + uniforms.translucencyViewAlpha.value = material.translucencyViewAlpha; + uniforms.translucencyViewPower.value = material.translucencyViewPower; + + uniforms.anisotropyMap.value = material.anisotropyMap; + uniforms.anisotropy.value = material.anisotropy; + uniforms.anisotropyRotation.value = material.anisotropyRotation; + uniforms.anisotropyRotationMap.value = material.anisotropyRotationMap; + + uniforms.ambient.value = material.ambient; + uniforms.emissive.value = material.emissive; + uniforms.falloffColor.value = material.falloffColor; + uniforms.specular.value = material.specular; + uniforms.translucency.value = material.translucency; + + }; + + function refreshUniformsLambert ( uniforms, material ) { + + uniforms.ambient.value = material.ambient; + uniforms.emissive.value = material.emissive; + + if ( material.wrapAround ) { + + uniforms.wrapRGB.value.copy( material.wrapRGB ); + + } + + }; + + function refreshUniformsLights ( uniforms, lights ) { + + uniforms.ambientLightColor.value = lights.ambient; + + uniforms.directionalLightColor.value = lights.directional.colors; + uniforms.directionalLightDirection.value = lights.directional.positions; + + uniforms.pointLightColor.value = lights.point.colors; + uniforms.pointLightPosition.value = lights.point.positions; + uniforms.pointLightDistance.value = lights.point.distances; + uniforms.pointLightDecayExponent.value = lights.point.decayExponents; + + uniforms.spotLightColor.value = lights.spot.colors; + uniforms.spotLightPosition.value = lights.spot.positions; + uniforms.spotLightDistance.value = lights.spot.distances; + uniforms.spotLightDecayExponent.value = lights.spot.decayExponents; + uniforms.spotLightDirection.value = lights.spot.directions; + uniforms.spotLightAngleCos.value = lights.spot.anglesCos; + uniforms.spotLightExponent.value = lights.spot.exponents; + + uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; + uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; + uniforms.hemisphereLightDirection.value = lights.hemi.positions; + + uniforms.areaLightColor.value = lights.area.colors; + uniforms.areaLightPosition.value = lights.area.positions; + uniforms.areaLightDistance.value = lights.area.distances; + uniforms.areaLightDecayExponent.value = lights.area.decayExponents; + uniforms.areaLightWidth.value = lights.area.widths; + uniforms.areaLightHeight.value = lights.area.heights; + + }; + + function refreshUniformsShadow ( uniforms, lights ) { + + if ( uniforms.shadowMatrix ) { + + var j = 0; + + for ( var i = 0, il = lights.length; i < il; i ++ ) { + + var light = lights[ i ]; + + if ( ! light.castShadow ) continue; + + if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) { + + uniforms.shadowMap.value[ j ] = light.shadowMap; + uniforms.shadowMapSize.value[ j ] = light.shadowMapSize; + + uniforms.shadowMatrix.value[ j ] = light.shadowMatrix; + + uniforms.shadowDarkness.value[ j ] = light.shadowDarkness; + uniforms.shadowBias.value[ j ] = light.shadowBias; + + j ++; + + } + + } + + } + + }; + + // Uniforms (load to GPU) + + function loadUniformsMatrices ( uniforms, object ) { + + _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements ); + + if ( uniforms.normalMatrix ) { + + _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements ); + + } + + }; + + function getTextureUnit() { + + var textureUnit = _usedTextureUnits; + + if ( textureUnit >= _maxTextures ) { + + THREE.onwarning( "WebGLRenderer: trying to use " + textureUnit + " texture units while this GPU supports only " + _maxTextures ); + + } + + _usedTextureUnits += 1; + + return textureUnit; + + }; + + function loadUniformsGeneric ( program, uniforms ) { + + var uniform, value, type, location, texture, textureUnit, i, il, j, jl, offset; + + for ( j = 0, jl = uniforms.length; j < jl; j ++ ) { + + location = program.uniforms[ uniforms[ j ][ 1 ] ]; + if ( !location ) continue; + + uniform = uniforms[ j ][ 0 ]; + + type = uniform.type; + value = uniform.value; + + if ( type === "i" ) { // single integer + + _gl.uniform1i( location, value ); + + } else if ( type === "f" ) { // single float + + _gl.uniform1f( location, value ); + + } else if ( type === "v2" ) { // single THREE.Vector2 + + _gl.uniform2f( location, value.x, value.y ); + + } else if ( type === "v3" ) { // single THREE.Vector3 + + _gl.uniform3f( location, value.x, value.y, value.z ); + + } else if ( type === "v4" ) { // single THREE.Vector4 + + _gl.uniform4f( location, value.x, value.y, value.z, value.w ); + + } else if ( type === "c" ) { // single THREE.Color + + _gl.uniform3f( location, value.r, value.g, value.b ); + + } else if ( type === "iv1" ) { // flat array of integers (JS or typed array) + + _gl.uniform1iv( location, value ); + + } else if ( type === "iv" ) { // flat array of integers with 3 x N size (JS or typed array) + + _gl.uniform3iv( location, value ); + + } else if ( type === "fv1" ) { // flat array of floats (JS or typed array) + + _gl.uniform1fv( location, value ); + + } else if ( type === "fv" ) { // flat array of floats with 3 x N size (JS or typed array) + + _gl.uniform3fv( location, value ); + + } else if ( type === "v2v" ) { // array of THREE.Vector2 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 2 * value.length ); + + } + + for ( i = 0, il = value.length; i < il; i ++ ) { + + offset = i * 2; + + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; + + } + + _gl.uniform2fv( location, uniform._array ); + + } else if ( type === "v3v" ) { // array of THREE.Vector3 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 3 * value.length ); + + } + + for ( i = 0, il = value.length; i < il; i ++ ) { + + offset = i * 3; + + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; + uniform._array[ offset + 2 ] = value[ i ].z; + + } + + _gl.uniform3fv( location, uniform._array ); + + } else if ( type === "v4v" ) { // array of THREE.Vector4 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 4 * value.length ); + + } + + for ( i = 0, il = value.length; i < il; i ++ ) { + + offset = i * 4; + + uniform._array[ offset ] = value[ i ].x; + uniform._array[ offset + 1 ] = value[ i ].y; + uniform._array[ offset + 2 ] = value[ i ].z; + uniform._array[ offset + 3 ] = value[ i ].w; + + } + + _gl.uniform4fv( location, uniform._array ); + + } else if ( type === "m4") { // single THREE.Matrix4 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 16 ); + + } + + value.flattenToArray( uniform._array ); + _gl.uniformMatrix4fv( location, false, uniform._array ); + + } else if ( type === "m4v" ) { // array of THREE.Matrix4 + + if ( uniform._array === undefined ) { + + uniform._array = new Float32Array( 16 * value.length ); + + } + + for ( i = 0, il = value.length; i < il; i ++ ) { + + value[ i ].flattenToArrayOffset( uniform._array, i * 16 ); + + } + + _gl.uniformMatrix4fv( location, false, uniform._array ); + + } else if ( type === "t" ) { // single THREE.Texture (2d or cube) + + texture = value; + textureUnit = getTextureUnit(); + + _gl.uniform1i( location, textureUnit ); + + if ( !texture ) continue; + + if ( texture.image instanceof Array && texture.image.length === 6 ) { + + setCubeTexture( texture, textureUnit ); + + } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { + + setCubeTextureDynamic( texture, textureUnit ); + + } else { + + _this.setTexture( texture, textureUnit ); + + } + + } else if ( type === "tv" ) { // array of THREE.Texture (2d) + + if ( uniform._array === undefined ) { + + uniform._array = []; + + } + + for( i = 0, il = uniform.value.length; i < il; i ++ ) { + + uniform._array[ i ] = getTextureUnit(); + + } + + _gl.uniform1iv( location, uniform._array ); + + for( i = 0, il = uniform.value.length; i < il; i ++ ) { + + texture = uniform.value[ i ]; + textureUnit = uniform._array[ i ]; + + if ( !texture ) continue; + + _this.setTexture( texture, textureUnit ); + + } + + } else { + + THREE.onwarning( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); + + } + + } + + }; + + function setupMatrices ( object, camera ) { + + object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + object._normalMatrix.getNormalMatrix( object._modelViewMatrix ); + + }; + + // + + + function setColorLinear( array, offset, color, intensity ) { + + array[ offset ] = color.r * intensity; + array[ offset + 1 ] = color.g * intensity; + array[ offset + 2 ] = color.b * intensity; + + }; + + function setupLights ( program, lights ) { + + var l, ll, light, n, + r = 0, g = 0, b = 0, + color, skyColor, groundColor, + intensity, intensitySq, + position, + distance, + + zlights = _lights, + + dirColors = zlights.directional.colors, + dirPositions = zlights.directional.positions, + + pointColors = zlights.point.colors, + pointPositions = zlights.point.positions, + pointDistances = zlights.point.distances, + pointDecayExponents = zlights.point.decayExponents, + + spotColors = zlights.spot.colors, + spotPositions = zlights.spot.positions, + spotDistances = zlights.spot.distances, + spotDecayExponents = zlights.spot.decayExponents, + spotDirections = zlights.spot.directions, + spotAnglesCos = zlights.spot.anglesCos, + spotExponents = zlights.spot.exponents, + + hemiSkyColors = zlights.hemi.skyColors, + hemiGroundColors = zlights.hemi.groundColors, + hemiPositions = zlights.hemi.positions, + + areaColors = zlights.area.colors, + areaPositions = zlights.area.positions, + areaDistances = zlights.area.distances, + areaDecayExponents = zlights.area.decayExponents, + areaWidths = zlights.area.widths, + areaHeights = zlights.area.heights, + + dirLength = 0, + pointLength = 0, + spotLength = 0, + hemiLength = 0, + areaLength = 0, + + dirCount = 0, + pointCount = 0, + spotCount = 0, + hemiCount = 0, + areaCount = 0, + + dirOffset = 0, + pointOffset = 0, + spotOffset = 0, + hemiOffset = 0, + areaOffset = 0; + + for ( l = 0, ll = lights.length; l < ll; l ++ ) { + + light = lights[ l ]; + + if ( light.onlyShadow ) continue; + + color = light.color; + intensity = light.intensity; + distance = light.distance; + + if ( light instanceof THREE.AmbientLight ) { + + if ( ! light.visible ) continue; + + r += color.r; + g += color.g; + b += color.b; + + } else if ( light instanceof THREE.DirectionalLight ) { + + dirCount += 1; + + if ( ! light.visible ) continue; + + _direction.setFromMatrixPosition( light.matrixWorld ); + _vector3.setFromMatrixPosition( light.target.matrixWorld ); + _direction.sub( _vector3 ); + _direction.normalize(); + + // skip lights with undefined direction + // these create troubles in OpenGL (making pixel black) + + if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; + + dirOffset = dirLength * 3; + + dirPositions[ dirOffset ] = _direction.x; + dirPositions[ dirOffset + 1 ] = _direction.y; + dirPositions[ dirOffset + 2 ] = _direction.z; + + + setColorLinear( dirColors, dirOffset, color, intensity ); + + dirLength += 1; + + } else if ( light instanceof THREE.PointLight ) { + + pointCount += 1; + + if ( ! light.visible ) continue; + + pointOffset = pointLength * 3; + + setColorLinear( pointColors, pointOffset, color, intensity ); + + _vector3.setFromMatrixPosition( light.matrixWorld ); + + pointPositions[ pointOffset ] = _vector3.x; + pointPositions[ pointOffset + 1 ] = _vector3.y; + pointPositions[ pointOffset + 2 ] = _vector3.z; + + pointDistances[ pointLength ] = distance; + + if( light.physicalFalloff ) { + // magic value of -1 switches the equation to UE4 physical quadratic falloff. + pointDecayExponents[ pointLength ] = -1.0; + } + else { + pointDecayExponents[ pointLength ] = ( distance === 0 ) ? 0.0 : light.decayExponent; + } + + pointLength += 1; + + } else if ( light instanceof THREE.SpotLight ) { + + spotCount += 1; + + if ( ! light.visible ) continue; + + spotOffset = spotLength * 3; + + setColorLinear( spotColors, spotOffset, color, intensity ); + + _vector3.setFromMatrixPosition( light.matrixWorld ); + + spotPositions[ spotOffset ] = _vector3.x; + spotPositions[ spotOffset + 1 ] = _vector3.y; + spotPositions[ spotOffset + 2 ] = _vector3.z; + + spotDistances[ spotLength ] = distance; + + if( light.physicalFalloff ) { + // magic value of -1 switches the equation to UE4 physical quadratic falloff. + spotDecayExponents[ pointLength ] = -1.0; + } + else { + spotDecayExponents[ pointLength ] = ( distance === 0 ) ? 0.0 : light.decayExponent; + } + + _direction.copy( _vector3 ); + _vector3.setFromMatrixPosition( light.target.matrixWorld ); + _direction.sub( _vector3 ); + _direction.normalize(); + + spotDirections[ spotOffset ] = _direction.x; + spotDirections[ spotOffset + 1 ] = _direction.y; + spotDirections[ spotOffset + 2 ] = _direction.z; + + spotAnglesCos[ spotLength ] = Math.cos( light.angle ); + spotExponents[ spotLength ] = light.exponent; + + spotLength += 1; + + } else if ( light instanceof THREE.HemisphereLight ) { + + hemiCount += 1; + + if ( ! light.visible ) continue; + + _direction.setFromMatrixPosition( light.matrixWorld ); + _direction.normalize(); + + // skip lights with undefined direction + // these create troubles in OpenGL (making pixel black) + + if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; + + hemiOffset = hemiLength * 3; + + hemiPositions[ hemiOffset ] = _direction.x; + hemiPositions[ hemiOffset + 1 ] = _direction.y; + hemiPositions[ hemiOffset + 2 ] = _direction.z; + + skyColor = light.color; + groundColor = light.groundColor; + + setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); + setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); + + hemiLength += 1; + + } else if ( light instanceof THREE.AreaLight ) { + + areaCount += 1; + + if ( ! light.visible ) continue; + + areaOffset = areaLength * 3; + + setColorLinear( areaColors, areaOffset, color, intensity ); + + _vector3.setFromMatrixPosition( light.matrixWorld ); + + areaPositions[ areaOffset ] = _vector3.x; + areaPositions[ areaOffset + 1 ] = _vector3.y; + areaPositions[ areaOffset + 2 ] = _vector3.z; + + areaDistances[ areaLength ] = distance; + areaDecayExponents[ areaLength ] = light.decayExponent; + + light.matrixWorld.extractBasis( _width, _height, _vector3 ); + _width.multiplyScalar( light.width ); + _height.multiplyScalar( light.height ); + + areaWidths[ areaOffset ] = _width.x; + areaWidths[ areaOffset + 1 ] = _width.y; + areaWidths[ areaOffset + 2 ] = _width.z; + + areaHeights[ areaOffset ] = _height.x; + areaHeights[ areaOffset + 1 ] = _height.y; + areaHeights[ areaOffset + 2 ] = _height.z; + + areaLength += 1; + + } + + } + + // null eventual remains from removed lights + // (this is to avoid if in shader) + + for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0; + for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0; + for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0; + for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0; + for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0; + for ( l = areaLength * 3, ll = Math.max( areaColors.length, areaCount * 3 ); l < ll; l ++ ) areaColors[ l ] = 0.0; + + zlights.directional.length = dirLength; + zlights.point.length = pointLength; + zlights.spot.length = spotLength; + zlights.hemi.length = hemiLength; + zlights.area.length = areaLength; + + zlights.ambient[ 0 ] = r; + zlights.ambient[ 1 ] = g; + zlights.ambient[ 2 ] = b; + + }; + + // GL state setting + + this.setFaceCulling = function ( cullFace, frontFaceDirection ) { + + if ( cullFace === THREE.CullFaceNone ) { + + _gl.disable( _gl.CULL_FACE ); + + } else { + + if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) { + + _gl.frontFace( _gl.CW ); + + } else { + + _gl.frontFace( _gl.CCW ); + + } + + if ( cullFace === THREE.CullFaceBack ) { + + _gl.cullFace( _gl.BACK ); + + } else if ( cullFace === THREE.CullFaceFront ) { + + _gl.cullFace( _gl.FRONT ); + + } else { + + _gl.cullFace( _gl.FRONT_AND_BACK ); + + } + + _gl.enable( _gl.CULL_FACE ); + + } + + }; + + this.setMaterialFaces = function ( material ) { + + var doubleSided = material.side === THREE.DoubleSide; + var flipSided = material.side === THREE.BackSide; + + if ( _oldDoubleSided !== doubleSided ) { + + if ( doubleSided ) { + + _gl.disable( _gl.CULL_FACE ); + + } else { + + _gl.enable( _gl.CULL_FACE ); + + } + + _oldDoubleSided = doubleSided; + + } + + if ( _oldFlipSided !== flipSided ) { + + if ( flipSided ) { + + _gl.frontFace( _gl.CW ); + + } else { + + _gl.frontFace( _gl.CCW ); + + } + + _oldFlipSided = flipSided; + + } + + }; + + this.setDepthTest = function ( depthTest ) { + + if ( _oldDepthTest !== depthTest ) { + + if ( depthTest ) { + + _gl.enable( _gl.DEPTH_TEST ); + + } else { + + _gl.disable( _gl.DEPTH_TEST ); + + } + + _oldDepthTest = depthTest; + + } + + }; + + this.setDepthWrite = function ( depthWrite ) { + + if ( _oldDepthWrite !== depthWrite ) { + + _gl.depthMask( depthWrite ); + _oldDepthWrite = depthWrite; + + } + + }; + + function setLineWidth ( width ) { + + if ( width !== _oldLineWidth ) { + + _gl.lineWidth( width ); + + _oldLineWidth = width; + + } + + }; + + function setPolygonOffset ( polygonoffset, factor, units ) { + + if ( _oldPolygonOffset !== polygonoffset ) { + + if ( polygonoffset ) { + + _gl.enable( _gl.POLYGON_OFFSET_FILL ); + + } else { + + _gl.disable( _gl.POLYGON_OFFSET_FILL ); + + } + + _oldPolygonOffset = polygonoffset; + + } + + if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) { + + _gl.polygonOffset( factor, units ); + + _oldPolygonOffsetFactor = factor; + _oldPolygonOffsetUnits = units; + + } + + }; + + this.setBlending = function ( blending, blendEquation, blendSrc, blendDst ) { + + if ( blending !== _oldBlending ) { + + if ( blending === THREE.NoBlending ) { + + _gl.disable( _gl.BLEND ); + + } else if ( blending === THREE.AdditiveBlending ) { + + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE ); + + } else if ( blending === THREE.SubtractiveBlending ) { + + // TODO: Find blendFuncSeparate() combination + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR ); + + } else if ( blending === THREE.MultiplyBlending ) { + + // TODO: Find blendFuncSeparate() combination + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR ); + + } else if ( blending === THREE.CustomBlending ) { + + _gl.enable( _gl.BLEND ); + + } else { + + _gl.enable( _gl.BLEND ); + _gl.blendEquationSeparate( _gl.FUNC_ADD, _gl.FUNC_ADD ); + _gl.blendFuncSeparate( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA ); + + } + + _oldBlending = blending; + + } + + if ( blending === THREE.CustomBlending ) { + + if ( blendEquation !== _oldBlendEquation ) { + + _gl.blendEquation( paramThreeToGL( blendEquation ) ); + + _oldBlendEquation = blendEquation; + + } + + if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst ) { + + _gl.blendFunc( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ) ); + + _oldBlendSrc = blendSrc; + _oldBlendDst = blendDst; + + } + + } else { + + _oldBlendEquation = null; + _oldBlendSrc = null; + _oldBlendDst = null; + + } + + }; + + // Defines + + function generateDefines ( defines ) { + + var value, chunk, chunks = []; + + for ( var d in defines ) { + + value = defines[ d ]; + if ( value === false ) continue; + + chunk = "#define " + d + " " + value; + chunks.push( chunk ); + + } + + return chunks.join( "\n" ); + + }; + + // Shaders + + function buildProgram( shaderID, fragmentShader, vertexShader, uniforms, attributes, defines, parameters, index0AttributeName ) { + + var p, pl, d, program, code; + var simpleChunks = []; + var chunks = []; + + // Generate code + + if ( shaderID ) { + + chunks.push( shaderID ); + simpleChunks.push( shaderID ); + + } else { + + chunks.push( fragmentShader ); + chunks.push( vertexShader ); + + } + + for ( d in defines ) { + + chunks.push( d ); + chunks.push( defines[ d ] ); + simpleChunks.push( d ); + simpleChunks.push( defines[ d ] ); + + } + + for ( p in parameters ) { + + chunks.push( p ); + chunks.push( parameters[ p ] ); + + simpleChunks.push( p ); + simpleChunks.push( parameters[ p ] ); + + } + + code = chunks.join(); + var simpleCode = simpleChunks.join(); + + // Check if code has been already compiled + + for ( p = 0, pl = _programs.length; p < pl; p ++ ) { + + var programInfo = _programs[ p ]; + + if ( programInfo.code.length === code.length && programInfo.code === code ) { + + programInfo.usedTimes ++; + + return programInfo.program; + + } + + } + + var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC"; + + if ( parameters.shadowMapType === THREE.PCFShadowMap ) { + + shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF"; + + } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) { + + shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT"; + + } + + var customDefines = generateDefines( defines ); + + program = _gl.createProgram(); + + var supportsShaderTextureLOD = ( _glExtensionShaderTextureLOD !== null ); + + var prefix_vertex = [ + + "precision " + _precision + " float;", + "precision " + _precision + " int;", + + customDefines, + + _supportsVertexTextures ? "#define VERTEX_TEXTURES" : "", + + _this.gammaInput ? "#define GAMMA_INPUT" : "", + _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", + + "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, + "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, + "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, + "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, + "#define MAX_AREA_LIGHTS " + parameters.maxAreaLights, + + "#define MAX_SHADOWS " + parameters.maxShadows, + + "#define MAX_BONES " + parameters.maxBones, + + parameters.map ? "#define USE_MAP" : "", + parameters.opacityMap ? "#define USE_OPACITYMAP" : "", + parameters.falloffMap ? "#define USE_FALLOFFMAP" : "", + parameters.translucencyMap ? "#define USE_TRANSLUCENCYMAP" : "", + parameters.envMap ? "#define USE_ENVMAP" : "", + parameters.diffuseEnvMap ? "#define USE_DIFFUSEENVMAP" : "", + parameters.lightMap ? "#define USE_LIGHTMAP" : "", + parameters.emissiveMap ? "#define USE_EMISSIVEMAP" : "", + parameters.bumpMap ? "#define USE_BUMPMAP" : "", + parameters.reflectivityMap ? "#define USE_REFLECTIVITYMAP" : "", + parameters.roughnessMap ? "#define USE_ROUGHNESSMAP" : "", + parameters.metallicMap ? "#define USE_METALLICMAP" : "", + parameters.normalMap ? "#define USE_NORMALMAP" : "", + parameters.specularMap ? "#define USE_SPECULARMAP" : "", + parameters.vertexColors ? "#define USE_COLOR" : "", + parameters.clearCoat ? "#define CLEARCOAT" : "", + + parameters.anisotropy ? "#define ANISOTROPY" : "", + parameters.anisotropyMap ? "#define USE_ANISOTROPYMAP" : "", + ( parameters.anisotropy && parameters.anisotropyRotation ) ? "#define ANISOTROPYROTATION" : "", + ( parameters.anisotropy && parameters.anisotropyRotationMap ) ? "#define USE_ANISOTROPYROTATIONMAP" : "", + + parameters.skinning ? "#define USE_SKINNING" : "", + parameters.useVertexTexture ? "#define BONE_TEXTURE" : "", + + parameters.morphTargets ? "#define USE_MORPHTARGETS" : "", + parameters.morphNormals ? "#define USE_MORPHNORMALS" : "", + parameters.wrapAround ? "#define WRAP_AROUND" : "", + parameters.doubleSided ? "#define DOUBLE_SIDED" : "", + parameters.flipSided ? "#define FLIP_SIDED" : "", + + parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", + parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", + parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", + parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", + + parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "", + + "uniform mat4 modelMatrix;", + "uniform mat4 modelViewMatrix;", + "uniform mat4 projectionMatrix;", + "uniform mat4 viewMatrix;", + "uniform mat3 normalMatrix;", + "uniform vec3 cameraPosition;", + + "attribute vec3 position;", + "attribute vec3 normal;", + "attribute vec2 uv;", + "attribute vec2 uv2;", + + "#ifdef USE_COLOR", + + "attribute vec3 color;", + + "#endif", + + "#ifdef USE_MORPHTARGETS", + + "attribute vec3 morphTarget0;", + "attribute vec3 morphTarget1;", + "attribute vec3 morphTarget2;", + "attribute vec3 morphTarget3;", + + "#ifdef USE_MORPHNORMALS", + + "attribute vec3 morphNormal0;", + "attribute vec3 morphNormal1;", + "attribute vec3 morphNormal2;", + "attribute vec3 morphNormal3;", + + "#else", + + "attribute vec3 morphTarget4;", + "attribute vec3 morphTarget5;", + "attribute vec3 morphTarget6;", + "attribute vec3 morphTarget7;", + + "#endif", + + "#endif", + + "#ifdef USE_SKINNING", + + "attribute vec4 skinIndex;", + "attribute vec4 skinWeight;", + + "#endif", + + "" + + ].join("\n"); + + + var prefix_fragment = [ + + "precision " + _precision + " float;", + "precision " + _precision + " int;", + + ( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "", + + customDefines, + + "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, + "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, + "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, + "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, + "#define MAX_AREA_LIGHTS " + parameters.maxAreaLights, + + "#define MAX_SHADOWS " + parameters.maxShadows, + + parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "", + + _this.gammaInput ? "#define GAMMA_INPUT" : "", + _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", + + ( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "", + ( parameters.useFog && parameters.fogExp ) ? "#define FOG_EXP2" : "", + + parameters.map ? "#define USE_MAP" : "", + parameters.opacityMap ? "#define USE_OPACITYMAP" : "", + parameters.falloffMap ? "#define USE_FALLOFFMAP" : "", + parameters.translucencyMap ? "#define USE_TRANSLUCENCYMAP" : "", + parameters.envMap ? "#define USE_ENVMAP" : "", + parameters.diffuseEnvMap ? "#define USE_DIFFUSEENVMAP" : "", + parameters.lightMap ? "#define USE_LIGHTMAP" : "", + parameters.emissiveMap ? "#define USE_EMISSIVEMAP" : "", + parameters.bumpMap ? "#define USE_BUMPMAP" : "", + parameters.reflectivityMap ? "#define USE_REFLECTIVITYMAP" : "", + parameters.roughnessMap ? "#define USE_ROUGHNESSMAP" : "", + parameters.metallicMap ? "#define USE_METALLICMAP" : "", + parameters.normalMap ? "#define USE_NORMALMAP" : "", + parameters.specularMap ? "#define USE_SPECULARMAP" : "", + parameters.vertexColors ? "#define USE_COLOR" : "", + parameters.clearCoat ? "#define CLEARCOAT" : "", + + parameters.translucency ? "#define TRANSLUCENCY" : "", + + parameters.anisotropy ? "#define ANISOTROPY" : "", + parameters.anisotropyMap ? "#define USE_ANISOTROPYMAP" : "", + ( parameters.anisotropy && parameters.anisotropyRotation ) ? "#define ANISOTROPYROTATION" : "", + ( parameters.anisotropy && parameters.anisotropyRotationMap ) ? "#define USE_ANISOTROPYROTATIONMAP" : "", + + parameters.falloff ? "#define FALLOFF" : "", + + parameters.wrapAround ? "#define WRAP_AROUND" : "", + parameters.doubleSided ? "#define DOUBLE_SIDED" : "", + parameters.flipSided ? "#define FLIP_SIDED" : "", + + parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", + parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", + parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", + parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", + + supportsShaderTextureLOD ? "#define TEXTURE_CUBE_LOD_EXT" : "", + + "uniform mat4 viewMatrix;", + "uniform vec3 cameraPosition;", + "" + + ].join("\n"); + + var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader, shaderID, simpleCode ); + var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader, shaderID, simpleCode ); + + _gl.attachShader( program, glVertexShader, code ); + _gl.attachShader( program, glFragmentShader, code ); + + // Force a particular attribute to index 0. + // because potentially expensive emulation is done by browser if attribute 0 is disabled. + // And, color, for example is often automatically bound to index 0 so disabling it + if ( index0AttributeName !== undefined ) { + + _gl.bindAttribLocation( program, 0, index0AttributeName ); + + } + + _gl.linkProgram( program ); + + var programLogInfo = _gl.getProgramInfoLog( program ); + + if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) { + + var gl_error_message = _gl.getError(); + THREE.onerror( shaderID + ' shader program error: ' + gl_error_message + '\n ' + programLogInfo, { + shaderID: shaderID, + programInfo: programLogInfo, + glError: gl_error_message, + vertexShader: prefix_vertex + vertexShader, + fragmentShader: prefix_fragment + fragmentShader, + getProgramParameter_LINK_STATUS: _gl.getProgramParameter( program, _gl.LINK_STATUS ), + getProgramParameter_VALIDATE_STATUS: _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ), + getProgramParameter_ATTACHED_SHADERS: _gl.getProgramParameter( program, _gl.ATTACHED_SHADERS ), + getProgramParameter_ACTIVE_ATTRIBUTES: _gl.getProgramParameter( program, _gl.ACTIVE_ATTRIBUTES ), + getProgramParameter_ACTIVE_UNIFORMS: _gl.getProgramParameter( program, _gl.ACTIVE_UNIFORMS ), + gl_MAX_VARYING_VECTORS: _gl.getParameter(_gl.MAX_VARYING_VECTORS), + gl_MAX_VERTEX_ATTRIBS: _gl.getParameter(_gl.MAX_VERTEX_ATTRIBS), + gl_MAX_VERTEX_UNIFORM_VECTORS: _gl.getParameter(_gl.MAX_VERTEX_UNIFORM_VECTORS), + gl_MAX_VERTEX_TEXTURE_IMAGE_UNITS: _gl.getParameter(_gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS), + gl_MAX_FRAGMENT_UNIFORM_VECTORS: _gl.getParameter(_gl.MAX_FRAGMENT_UNIFORM_VECTORS), + gl_MAX_TEXTURE_IMAGE_UNITS: _gl.getParameter(_gl.MAX_TEXTURE_IMAGE_UNITS) + } ); + } + + // clean up + + _gl.deleteShader( glFragmentShader ); + _gl.deleteShader( glVertexShader ); + + program.uniforms = {}; + program.attributes = {}; + + var identifiers, u, a, i; + + // cache uniform locations + + identifiers = [ + + 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition', + 'morphTargetInfluences' + + ]; + + if ( parameters.useVertexTexture ) { + + identifiers.push( 'boneTexture' ); + identifiers.push( 'boneTextureWidth' ); + identifiers.push( 'boneTextureHeight' ); + + } else { + + identifiers.push( 'boneGlobalMatrices' ); + + } + + for ( u in uniforms ) { + + identifiers.push( u ); + + } + + cacheUniformLocations( program, identifiers ); + + // cache attributes locations + + identifiers = [ + + "position", "normal", "uv", "uv2", "tangent", "color", + "skinIndex", "skinWeight", "lineDistance" + + ]; + + for ( i = 0; i < parameters.maxMorphTargets; i ++ ) { + + identifiers.push( "morphTarget" + i ); + + } + + for ( i = 0; i < parameters.maxMorphNormals; i ++ ) { + + identifiers.push( "morphNormal" + i ); + + } + + for ( a in attributes ) { + + identifiers.push( a ); + + } + + cacheAttributeLocations( program, identifiers ); + + program.id = _programs_counter ++; + + _programs.push( { program: program, code: code, usedTimes: 1 } ); + + _this.info.memory.programs = _programs.length; + + return program; + + }; + + // Shader parameters cache + + function cacheUniformLocations ( program, identifiers ) { + + var i, l, id; + + for( i = 0, l = identifiers.length; i < l; i ++ ) { + + id = identifiers[ i ]; + program.uniforms[ id ] = _gl.getUniformLocation( program, id ); + + } + + }; + + function cacheAttributeLocations ( program, identifiers ) { + + var i, l, id; + + for( i = 0, l = identifiers.length; i < l; i ++ ) { + + id = identifiers[ i ]; + program.attributes[ id ] = _gl.getAttribLocation( program, id ); + + } + + }; + + function addLineNumbers ( string ) { + + var chunks = string.split( "\n" ); + + for ( var i = 0, il = chunks.length; i < il; i ++ ) { + + // Chrome reports shader errors on lines + // starting counting from 1 + + chunks[ i ] = ( i + 1 ) + ": " + chunks[ i ]; + + } + + return chunks.join( "\n" ); + + }; + + function getShader ( type, string, shaderID, simpleCode ) { + + var shader; + + if ( type === "fragment" ) { + + shader = _gl.createShader( _gl.FRAGMENT_SHADER ); + + } else if ( type === "vertex" ) { + + shader = _gl.createShader( _gl.VERTEX_SHADER ); + + } + + _gl.shaderSource( shader, string ); + _gl.compileShader( shader ); + + if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) { + + THREE.onerror( "shader error: " + shaderID + "." + type, { + getShaderParameter: _gl.getShaderParameter( shader, _gl.COMPILE_STATUS ), + shaderInfoLog: _gl.getShaderInfoLog( shader ), + shaderCode: addLineNumbers( string ), + getError: _gl.getError(), + simpleCode: simpleCode, + gl_MAX_VARYING_VECTORS: _gl.getParameter(_gl.MAX_VARYING_VECTORS), + gl_MAX_VERTEX_ATTRIBS: _gl.getParameter(_gl.MAX_VERTEX_ATTRIBS), + gl_MAX_VERTEX_UNIFORM_VECTORS: _gl.getParameter(_gl.MAX_VERTEX_UNIFORM_VECTORS), + gl_MAX_VERTEX_TEXTURE_IMAGE_UNITS: _gl.getParameter(_gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS), + gl_MAX_FRAGMENT_UNIFORM_VECTORS: _gl.getParameter(_gl.MAX_FRAGMENT_UNIFORM_VECTORS), + gl_MAX_TEXTURE_IMAGE_UNITS: _gl.getParameter(_gl.MAX_TEXTURE_IMAGE_UNITS) + } ); + + return null; + + } + + return shader; + + }; + + // Textures + + function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) { + + if ( isImagePowerOfTwo ) { + + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) ); + + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) ); + + } else { + + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); + + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); + + } + + if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) { + + if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) { + + _gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) ); + texture.__oldAnisotropy = texture.anisotropy; + + } + + } + + }; + + var _reportIfError = function ( description, optionalData ) { + var errorCode = _gl.getError(); + if( errorCode === _gl.NO_ERROR ) { + return; + } + var errorMessage = ""; + if( errorCode === _gl.OUT_OF_MEMORY ) { + errorMessage = "OUT_OF_MEMORY"; + } + else if( errorCode === _gl.INVALID_ENUM ) { + errorMessage = "INVALID_ENUM"; + } + else if( errorCode === _gl.INVALID_OPERATION ) { + errorMessage = "INVALID_OPERATION"; + } + else if( errorCode === _gl.INVALID_VALUE ) { + errorMessage = "INVALID_VALUE"; + } + else if( errorCode === _gl.INVALID_FRAMEBUFFER_OPERATION ) { + errorMessage = "INVALID_FRAMEBUFFER_OPERATION"; + } + else if( errorCode === _gl.CONTEXT_LOST_WEBGL ) { + errorMessage = "CONTEXT_LOST_WEBGL"; + } + else if( errorCode === _gl.NO_ERROR ) { + errorMessage = "NO_ERROR"; + } + else { + errorMessage = "Unknown code: " + errorCode; + } + THREE.onerror( "WebGL Error: " + errorMessage + " (" + description + ")", optionalData ); + }; + + this.setTexture = function ( texture, slot ) { + + if ( texture.needsUpdate ) { + + if ( ! texture.__webglInit ) { + + texture.__webglInit = true; + + texture.addEventListener( 'dispose', onTextureDispose ); + + texture.__webglTexture = _gl.createTexture(); + + _this.info.memory.textures ++; + + } + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); + + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + + var image = texture.image, + isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), + glFormat = paramThreeToGL( texture.format ), + glType = paramThreeToGL( texture.type ); + + setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo ); + + var mipmap, mipmaps = texture.mipmaps; + + if ( texture instanceof THREE.DataTexture ) { + + // use manually created mipmaps if available + // if there are no manual mipmaps + // set 0 level mipmap and then use GL to generate other mipmap levels + + if ( mipmaps.length > 0 && isImagePowerOfTwo ) { + + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + + mipmap = mipmaps[ i ]; + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + _reportIfError( "_gl.texImage2D DataTexture Mipmaps, texture.name: " + texture.name, texture ); + } + + texture.generateMipmaps = false; + + } else { + + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); + _reportIfError( "_gl.texImage2D DataTexture, texture.name: " + texture.name, texture ); + } + + } else if ( texture instanceof THREE.CompressedTexture ) { + + for( var i = 0, il = mipmaps.length; i < il; i ++ ) { + + mipmap = mipmaps[ i ]; + if ( texture.format!==THREE.RGBAFormat ) { + _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + _reportIfError( "_gl.texImage2D CompressedTexture Non RGBA, texture.name: " + texture.name, texture ); + } else { + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + _reportIfError( "_gl.texImage2D CompressedTexture, texture.name: " + texture.name, texture ); + } + + } + + } else { // regular Texture (image, video, canvas) + + // use manually created mipmaps if available + // if there are no manual mipmaps + // set 0 level mipmap and then use GL to generate other mipmap levels + + if ( mipmaps.length > 0 && isImagePowerOfTwo ) { + + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + + mipmap = mipmaps[ i ]; + _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); + _reportIfError( "_gl.texImage2D Mipmaps, texture.name: " + texture.name, texture ); + + } + + texture.generateMipmaps = false; + + } else { + + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image ); + _reportIfError( "_gl.texImage2D, texture.name: " + texture.name, texture ); + + } + + } + + if ( texture.generateMipmaps && isImagePowerOfTwo ) { + _gl.generateMipmap( _gl.TEXTURE_2D ); + _reportIfError( "_gl.generateMipmap, texture.name: " + texture.name, texture ); + } + + + texture.needsUpdate = false; + + if ( texture.onUpdate ) texture.onUpdate(); + + } else { + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); + + } + + }; + + function clampToMaxSize ( image, maxSize ) { + + if ( image.width <= maxSize && image.height <= maxSize ) { + + return image; + + } + + // Warning: Scaling through the canvas will only work with images that use + // premultiplied alpha. + + var maxDimension = Math.max( image.width, image.height ); + var newWidth = Math.floor( image.width * maxSize / maxDimension ); + var newHeight = Math.floor( image.height * maxSize / maxDimension ); + + var canvas = document.createElement( 'canvas' ); + canvas.width = newWidth; + canvas.height = newHeight; + + var ctx = canvas.getContext( "2d" ); + ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight ); + + return canvas; + + } + + function setCubeTexture ( texture, slot ) { + + if ( texture.image.length === 6 ) { + + if ( texture.needsUpdate ) { + + if ( ! texture.image.__webglTextureCube ) { + + texture.addEventListener( 'dispose', onTextureDispose ); + + texture.image.__webglTextureCube = _gl.createTexture(); + + _this.info.memory.textures ++; + + } + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); + + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + + var isCompressed = texture instanceof THREE.CompressedTexture; + + var cubeImage = []; + + for ( var i = 0; i < 6; i ++ ) { + + if ( _this.autoScaleCubemaps && ! isCompressed ) { + + cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize ); + + } else { + + cubeImage[ i ] = texture.image[ i ]; + + } + + } + + var image = cubeImage[ 0 ], + isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), + glFormat = paramThreeToGL( texture.format ), + glType = paramThreeToGL( texture.type ); + + setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo ); + + for ( var i = 0; i < 6; i ++ ) { + + if( !isCompressed ) { + + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); + _reportIfError( "_gl.texImage2D CubeMap, texture.name: " + texture.name, { texture: texture, cubeImage: cubeImage, index: i } ); + + } else { + + var mipmap, mipmaps = cubeImage[ i ].mipmaps; + + for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { + + mipmap = mipmaps[ j ]; + if ( texture.format!==THREE.RGBAFormat ) { + + _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + _reportIfError( "_gl.compressedTexImage2D CubeMap Mipmaps Compressed, texture.name: " + texture.name, texture ); + + } else { + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + _reportIfError( "_gl.texImage2D CubeMap Mipmaps Compressed RGBA, texture.name: " + texture.name, texture ); + } + + } + } + } + + if ( texture.generateMipmaps && isImagePowerOfTwo ) { + + _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + _reportIfError( "_gl.generateMipmap CubeMap Mipmaps, texture.name: " + texture.name, texture ); + + } + + texture.needsUpdate = false; + + if ( texture.onUpdate ) texture.onUpdate(); + + } else { + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); + + } + + } + + }; + + function setCubeTextureDynamic ( texture, slot ) { + + _gl.activeTexture( _gl.TEXTURE0 + slot ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture ); + + }; + + // Render targets + + function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) { + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 ); + + }; + + function setupRenderBuffer ( renderbuffer, renderTarget ) { + + _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); + + var optionsString = ""; + + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + + optionsString = "renderTarget: " + renderTarget.width + "+" + renderTarget.height + " DEPTH_ATTACHMENT"; + + /* For some reason this is not working. Defaulting to RGBA4. + } else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + */ + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); + + optionsString = "renderTarget: " + renderTarget.width + "+" + renderTarget.height + " DEPTH_STENCIL_ATTACHMENT"; + + } else { + + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); + + optionsString = "renderTarget: " + renderTarget.width + "+" + renderTarget.height + " RGBA4"; + + } + + if (_gl.checkFramebufferStatus(_gl.FRAMEBUFFER) != _gl.FRAMEBUFFER_COMPLETE) { + console.log( renderTarget ); + throw new Error('(A) Rendering to this texture (renderTarget.name: ' + renderTarget.name + ') is not supported (incomplete framebuffer) ' + optionsString ); + } + + }; + + this.setRenderTarget = function ( renderTarget ) { + + var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); + + if ( renderTarget && ! renderTarget.__webglFramebuffer ) { + + if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true; + if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true; + + renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); + + renderTarget.__webglTexture = _gl.createTexture(); + + _this.info.memory.textures ++; + + // Setup texture, create render and frame buffers + + var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ), + glFormat = paramThreeToGL( renderTarget.format ), + glType = paramThreeToGL( renderTarget.type ); + + if ( isCube ) { + + renderTarget.__webglFramebuffer = []; + renderTarget.__webglRenderbuffer = []; + + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); + setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo ); + + for ( var i = 0; i < 6; i ++ ) { + + renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer(); + + _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + _reportIfError( "_gl.texImage2D CubeMap, renderTarget.name: " + renderTarget.name, renderTarget ); + + setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); + setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget ); + + } + + if ( isTargetPowerOfTwo ) { + _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + _reportIfError( "_gl.generateMipmap, CubeMap, renderTarget.name: " + renderTarget.name, renderTarget ); + } + + } else { + + renderTarget.__webglFramebuffer = _gl.createFramebuffer(); + + if ( renderTarget.shareDepthFrom ) { + + renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer; + + } else { + + renderTarget.__webglRenderbuffer = _gl.createRenderbuffer(); + + } + + _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); + setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo ); + + _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + _reportIfError( "_gl.texImage2D, renderTarget.name: " + renderTarget.name, renderTarget ); + + setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D ); + + if ( renderTarget.shareDepthFrom ) { + + var optionsString = "glFormat: " + glFormat + " glType: " + glType; + + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { + + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); + + optionsString = " renderTarget: " + renderTarget.width + "+" + renderTarget.height + " DEPTH_ATTACHMENT"; + + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); + + optionsString = " renderTarget: " + renderTarget.width + "+" + renderTarget.height + " DEPTH_STENCIL_ATTACHMENT"; + + } + + if (_gl.checkFramebufferStatus(_gl.FRAMEBUFFER) != _gl.FRAMEBUFFER_COMPLETE) { + throw new Error('(B) Rendering to this texture (renderTarget.name: ' + renderTarget.name + ') is not supported (incomplete framebuffer) ' + optionsString ); + } + + } else { + + setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget ); + + } + + if ( isTargetPowerOfTwo ) { + _gl.generateMipmap( _gl.TEXTURE_2D ); + _reportIfError( "_gl.generateMipmap, renderTarget.name: " + renderTarget.name, renderTarget ); + } + + + } + + // Release everything + + if ( isCube ) { + + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); + + } else { + + _gl.bindTexture( _gl.TEXTURE_2D, null ); + + } + + _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); + _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); + + } + + var framebuffer, width, height, vx, vy; + + if ( renderTarget ) { + + if ( isCube ) { + + framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ]; + + } else { + + framebuffer = renderTarget.__webglFramebuffer; + + } + + width = renderTarget.width; + height = renderTarget.height; + + vx = 0; + vy = 0; + + } else { + + framebuffer = null; + + width = _viewportWidth; + height = _viewportHeight; + + vx = _viewportX; + vy = _viewportY; + + } + + if ( framebuffer !== _currentFramebuffer ) { + + _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); + _gl.viewport( vx, vy, width, height ); + + _currentFramebuffer = framebuffer; + + } + + _currentWidth = width; + _currentHeight = height; + + }; + + function updateRenderTargetMipmap ( renderTarget ) { + + if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { + + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); + _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); + _reportIfError( "_gl.generateMipmap CubeMap, renderTarget.name: " + renderTarget.name, renderTarget ); + _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); + + } else { + + _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); + _gl.generateMipmap( _gl.TEXTURE_2D ); + _reportIfError( "_gl.generateMipmap, renderTarget.name: " + renderTarget.name, renderTarget ); + _gl.bindTexture( _gl.TEXTURE_2D, null ); + + } + + }; + + // Fallback filters for non-power-of-2 textures + + function filterFallback ( f ) { + + if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) { + + return _gl.NEAREST; + + } + + return _gl.LINEAR; + + }; + + // Map three.js constants to WebGL constants + + function paramThreeToGL ( p ) { + + if ( p === THREE.RepeatWrapping ) return _gl.REPEAT; + if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; + if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; + + if ( p === THREE.NearestFilter ) return _gl.NEAREST; + if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST; + if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR; + + if ( p === THREE.LinearFilter ) return _gl.LINEAR; + if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST; + if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR; + + if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE; + if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4; + if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1; + if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5; + + if ( p === THREE.ByteType ) return _gl.BYTE; + if ( p === THREE.ShortType ) return _gl.SHORT; + if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT; + if ( p === THREE.IntType ) return _gl.INT; + if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; + if ( p === THREE.FloatType ) return _gl.FLOAT; + if ( p === THREE.HalfType ) return 0x8D61; + + if ( p === THREE.AlphaFormat ) return _gl.ALPHA; + if ( p === THREE.RGBFormat ) return _gl.RGB; + if ( p === THREE.RGBAFormat ) return _gl.RGBA; + if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE; + if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA; + + if ( p === THREE.AddEquation ) return _gl.FUNC_ADD; + if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT; + if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT; + + if ( p === THREE.ZeroFactor ) return _gl.ZERO; + if ( p === THREE.OneFactor ) return _gl.ONE; + if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR; + if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR; + if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA; + if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA; + if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA; + if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA; + + if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR; + if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; + if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; + + if ( _glExtensionCompressedTextureS3TC !== undefined ) { + + if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT; + if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT; + if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT; + if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT; + + } + + return 0; + + }; + + // Allocations + + function allocateBones ( object ) { + + if ( _supportsBoneTextures && object && object.useVertexTexture ) { + + return 1024; + + } else { + + // default for when object is not specified + // ( for example when prebuilding shader + // to be used with multiple objects ) + // + // - leave some extra space for other uniforms + // - limit here is ANGLE's 254 max uniform vectors + // (up to 54 should be safe) + + var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS ); + var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); + + var maxBones = nVertexMatrices; + + if ( object !== undefined && object instanceof THREE.SkinnedMesh ) { + + maxBones = Math.min( object.bones.length, maxBones ); + + if ( maxBones < object.bones.length ) { + + THREE.onwarning( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" ); + + } + + } + + return maxBones; + + } + + }; + + function allocateLights( lights ) { + + var dirLights = 0; + var pointLights = 0; + var spotLights = 0; + var hemiLights = 0; + var areaLights = 0; + + for ( var l = 0, ll = lights.length; l < ll; l ++ ) { + + var light = lights[ l ]; + + if ( light.onlyShadow || light.visible === false ) continue; + + if ( light instanceof THREE.DirectionalLight ) dirLights ++; + if ( light instanceof THREE.PointLight ) pointLights ++; + if ( light instanceof THREE.SpotLight ) spotLights ++; + if ( light instanceof THREE.HemisphereLight ) hemiLights ++; + if ( light instanceof THREE.AreaLight ) areaLights ++; + + } + + return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights, 'area': areaLights }; + + }; + + function allocateShadows( lights ) { + + var maxShadows = 0; + + for ( var l = 0, ll = lights.length; l < ll; l++ ) { + + var light = lights[ l ]; + + if ( ! light.castShadow ) continue; + + if ( light instanceof THREE.SpotLight ) maxShadows ++; + if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++; + + } + + return maxShadows; + + }; + + // Initialization + + function initGL() { + + try { + + var attributes = { + alpha: _alpha, + premultipliedAlpha: _premultipliedAlpha, + antialias: _antialias, + stencil: _stencil, + preserveDrawingBuffer: _preserveDrawingBuffer + }; + + _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes ); + + if ( _gl === null ) { + + THREE.onerror( 'Error creating WebGL context.' ); + + } + + } catch ( error ) { + + THREE.onerror( error ); + + } + + _glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' ); + _glExtensionTextureFloatLinear = _gl.getExtension( 'OES_texture_float_linear' ); + _glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' ); + _glExtensionShaderTextureLOD = _gl.getExtension( 'EXT_shader_texture_lod' ); + + _glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); + + _glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); + + if ( ! _glExtensionTextureFloat ) { + + console.log( 'THREE.WebGLRenderer: Float textures not supported.' ); + + } + + if ( ! _glExtensionStandardDerivatives ) { + + console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' ); + + } + + if ( ! _glExtensionShaderTextureLOD ) { + + console.log( 'THREE.WebGLRenderer: Shader texture LOD not supported.' ); + + } + + if ( ! _glExtensionTextureFilterAnisotropic ) { + + console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' ); + + } + + if ( ! _glExtensionCompressedTextureS3TC ) { + + console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' ); + + } + + if ( _gl.getShaderPrecisionFormat === undefined ) { + + _gl.getShaderPrecisionFormat = function() { + + return { + "rangeMin" : 1, + "rangeMax" : 1, + "precision" : 1 + }; + + } + } + + }; + + function setDefaultGLState () { + + _gl.clearColor( 0, 0, 0, 1 ); + _gl.clearDepth( 1 ); + _gl.clearStencil( 0 ); + + _gl.enable( _gl.DEPTH_TEST ); + _gl.depthFunc( _gl.LEQUAL ); + + _gl.frontFace( _gl.CCW ); + _gl.cullFace( _gl.BACK ); + _gl.enable( _gl.CULL_FACE ); + + _gl.enable( _gl.BLEND ); + _gl.blendEquation( _gl.FUNC_ADD ); + _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA ); + + _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); + + _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + + }; + + // default plugins (order is important) + + this.shadowMapPlugin = new THREE.ShadowMapPlugin(); + this.addPrePlugin( this.shadowMapPlugin ); + + this.addPostPlugin( new THREE.SpritePlugin() ); + this.addPostPlugin( new THREE.LensFlarePlugin() ); + +}; + +/** + * @author szimek / https://github.com/szimek/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.WebGLRenderTarget = function ( width, height, options, name ) { + + this.name = name || ""; + this.width = width; + this.height = height; + + options = options || {}; + + this.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping; + this.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping; + + this.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter; + this.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter; + + this.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1; + + this.offset = new THREE.Vector2( 0, 0 ); + this.repeat = new THREE.Vector2( 1, 1 ); + + this.format = options.format !== undefined ? options.format : THREE.RGBAFormat; + this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType; + + this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; + this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; + + this.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; + + this.shareDepthFrom = null; + +}; + +THREE.WebGLRenderTarget.prototype = { + + constructor: THREE.WebGLRenderTarget, + + clone: function () { + + var tmp = new THREE.WebGLRenderTarget( this.width, this.height, null, this.name + " Clone" ); + + tmp.wrapS = this.wrapS; + tmp.wrapT = this.wrapT; + + tmp.magFilter = this.magFilter; + tmp.minFilter = this.minFilter; + + tmp.anisotropy = this.anisotropy; + + tmp.offset.copy( this.offset ); + tmp.repeat.copy( this.repeat ); + + tmp.format = this.format; + tmp.type = this.type; + + tmp.depthBuffer = this.depthBuffer; + tmp.stencilBuffer = this.stencilBuffer; + + tmp.generateMipmaps = this.generateMipmaps; + + tmp.shareDepthFrom = this.shareDepthFrom; + + return tmp; + + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); + + } + +}; + +THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype ); + +/** + * @author alteredq / http://alteredqualia.com + */ + +THREE.WebGLRenderTargetCube = function ( width, height, options ) { + + THREE.WebGLRenderTarget.call( this, width, height, options ); + + this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 + +}; + +THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableVertex = function () { + + this.position = new THREE.Vector3(); + this.positionWorld = new THREE.Vector3(); + this.positionScreen = new THREE.Vector4(); + + this.visible = true; + +}; + +THREE.RenderableVertex.prototype.copy = function ( vertex ) { + + this.positionWorld.copy( vertex.positionWorld ); + this.positionScreen.copy( vertex.positionScreen ); + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableFace = function () { + + this.id = 0; + + this.v1 = new THREE.RenderableVertex(); + this.v2 = new THREE.RenderableVertex(); + this.v3 = new THREE.RenderableVertex(); + + this.centroidModel = new THREE.Vector3(); + + this.normalModel = new THREE.Vector3(); + + this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; + this.vertexNormalsLength = 0; + + this.color = null; + this.material = null; + this.uvs = [[]]; + + this.z = 0; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableObject = function () { + + this.id = 0; + + this.object = null; + this.z = 0; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableSprite = function () { + + this.id = 0; + + this.object = null; + + this.x = 0; + this.y = 0; + this.z = 0; + + this.rotation = 0; + this.scale = new THREE.Vector2(); + + this.material = null; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.RenderableLine = function () { + + this.id = 0; + + this.v1 = new THREE.RenderableVertex(); + this.v2 = new THREE.RenderableVertex(); + + this.vertexColors = [ new THREE.Color(), new THREE.Color() ]; + this.material = null; + + this.z = 0; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.GeometryUtils = { + + // Merge two geometries or geometry and geometry from object (using object's transform) + + merge: function ( geometry1, object2 /* mesh | geometry */, materialIndexOffset ) { + + var matrix, normalMatrix, + vertexOffset = geometry1.vertices.length, + uvPosition = geometry1.faceVertexUvs[ 0 ].length, + geometry2 = object2 instanceof THREE.Mesh ? object2.geometry : object2, + vertices1 = geometry1.vertices, + vertices2 = geometry2.vertices, + faces1 = geometry1.faces, + faces2 = geometry2.faces, + uvs1 = geometry1.faceVertexUvs[ 0 ], + uvs2 = geometry2.faceVertexUvs[ 0 ]; + + if ( materialIndexOffset === undefined ) materialIndexOffset = 0; + + if ( object2 instanceof THREE.Mesh ) { + + object2.matrixAutoUpdate && object2.updateMatrix(); + + matrix = object2.matrix; + + normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); + + } + + // vertices + + for ( var i = 0, il = vertices2.length; i < il; i ++ ) { + + var vertex = vertices2[ i ]; + + var vertexCopy = vertex.clone(); + + if ( matrix ) vertexCopy.applyMatrix4( matrix ); + + vertices1.push( vertexCopy ); + + } + + // faces + + for ( i = 0, il = faces2.length; i < il; i ++ ) { + + var face = faces2[ i ], faceCopy, normal, color, + faceVertexNormals = face.vertexNormals, + faceVertexColors = face.vertexColors; + + faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); + faceCopy.normal.copy( face.normal ); + + if ( normalMatrix ) { + + faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); + + } + + for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { + + normal = faceVertexNormals[ j ].clone(); + + if ( normalMatrix ) { + + normal.applyMatrix3( normalMatrix ).normalize(); + + } + + faceCopy.vertexNormals.push( normal ); + + } + + faceCopy.color.copy( face.color ); + + for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { + + color = faceVertexColors[ j ]; + faceCopy.vertexColors.push( color.clone() ); + + } + + faceCopy.materialIndex = face.materialIndex + materialIndexOffset; + + faceCopy.centroid.copy( face.centroid ); + + if ( matrix ) { + + faceCopy.centroid.applyMatrix4( matrix ); + + } + + faces1.push( faceCopy ); + + } + + // uvs + + for ( i = 0, il = uvs2.length; i < il; i ++ ) { + + var uv = uvs2[ i ], uvCopy = []; + + for ( var j = 0, jl = uv.length; j < jl; j ++ ) { + + uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); + + } + + uvs1.push( uvCopy ); + + } + + }, + + // Get random point in triangle (via barycentric coordinates) + // (uniform distribution) + // http://www.cgafaq.info/wiki/Random_Point_In_Triangle + + randomPointInTriangle: function () { + + var vector = new THREE.Vector3(); + + return function ( vectorA, vectorB, vectorC ) { + + var point = new THREE.Vector3(); + + var a = THREE.Math.random16(); + var b = THREE.Math.random16(); + + if ( ( a + b ) > 1 ) { + + a = 1 - a; + b = 1 - b; + + } + + var c = 1 - a - b; + + point.copy( vectorA ); + point.multiplyScalar( a ); + + vector.copy( vectorB ); + vector.multiplyScalar( b ); + + point.add( vector ); + + vector.copy( vectorC ); + vector.multiplyScalar( c ); + + point.add( vector ); + + return point; + + }; + + }(), + + // Get random point in face (triangle / quad) + // (uniform distribution) + + randomPointInFace: function ( face, geometry, useCachedAreas ) { + + var vA, vB, vC, vD; + + vA = geometry.vertices[ face.a ]; + vB = geometry.vertices[ face.b ]; + vC = geometry.vertices[ face.c ]; + + return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC ); + + }, + + // Get uniformly distributed random points in mesh + // - create array with cumulative sums of face areas + // - pick random number from 0 to total area + // - find corresponding place in area array by binary search + // - get random point in face + + randomPointsInGeometry: function ( geometry, n ) { + + var face, i, + faces = geometry.faces, + vertices = geometry.vertices, + il = faces.length, + totalArea = 0, + cumulativeAreas = [], + vA, vB, vC, vD; + + // precompute face areas + + for ( i = 0; i < il; i ++ ) { + + face = faces[ i ]; + + vA = vertices[ face.a ]; + vB = vertices[ face.b ]; + vC = vertices[ face.c ]; + + face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC ); + + totalArea += face._area; + + cumulativeAreas[ i ] = totalArea; + + } + + // binary search cumulative areas array + + function binarySearchIndices( value ) { + + function binarySearch( start, end ) { + + // return closest larger index + // if exact number is not found + + if ( end < start ) + return start; + + var mid = start + Math.floor( ( end - start ) / 2 ); + + if ( cumulativeAreas[ mid ] > value ) { + + return binarySearch( start, mid - 1 ); + + } else if ( cumulativeAreas[ mid ] < value ) { + + return binarySearch( mid + 1, end ); + + } else { + + return mid; + + } + + } + + var result = binarySearch( 0, cumulativeAreas.length - 1 ) + return result; + + } + + // pick random face weighted by face area + + var r, index, + result = []; + + var stats = {}; + + for ( i = 0; i < n; i ++ ) { + + r = THREE.Math.random16() * totalArea; + + index = binarySearchIndices( r ); + + result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true ); + + if ( ! stats[ index ] ) { + + stats[ index ] = 1; + + } else { + + stats[ index ] += 1; + + } + + } + + return result; + + }, + + // Get triangle area (half of parallelogram) + // http://mathworld.wolfram.com/TriangleArea.html + + triangleArea: function () { + + var vector1 = new THREE.Vector3(); + var vector2 = new THREE.Vector3(); + + return function ( vectorA, vectorB, vectorC ) { + + vector1.subVectors( vectorB, vectorA ); + vector2.subVectors( vectorC, vectorA ); + vector1.cross( vector2 ); + + return 0.5 * vector1.length(); + + }; + + }(), + + // Center geometry so that 0,0,0 is in center of bounding box + + center: function ( geometry ) { + + geometry.computeBoundingBox(); + + var bb = geometry.boundingBox; + + var offset = new THREE.Vector3(); + + offset.addVectors( bb.min, bb.max ); + offset.multiplyScalar( -0.5 ); + + geometry.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) ); + geometry.computeBoundingBox(); + + return offset; + + }, + + triangulateQuads: function ( geometry ) { + + var i, il, j, jl; + + var faces = []; + var faceVertexUvs = []; + + for ( i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) { + + faceVertexUvs[ i ] = []; + + } + + for ( i = 0, il = geometry.faces.length; i < il; i ++ ) { + + var face = geometry.faces[ i ]; + + faces.push( face ); + + for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) { + + faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] ); + + } + + } + + geometry.faces = faces; + geometry.faceVertexUvs = faceVertexUvs; + + geometry.computeCentroids(); + geometry.computeFaceNormals(); + geometry.computeVertexNormals(); + + if ( geometry.hasTangents ) geometry.computeTangents(); + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.ImageUtils = { + + crossOrigin: undefined, + + loadTexture: function ( url, mapping, onLoad, onError ) { + + var loader = new THREE.ImageLoader(); + loader.crossOrigin = this.crossOrigin; + + var texture = new THREE.Texture( undefined, mapping ); + + var image = loader.load( url, function () { + + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); + + } ); + + texture.image = image; + texture.sourceFile = url; + + return texture; + + }, + + loadCompressedTexture: function ( url, mapping, onLoad, onError ) { + + var texture = new THREE.CompressedTexture(); + texture.mapping = mapping; + + var request = new XMLHttpRequest(); + + request.onload = function () { + + var buffer = request.response; + var dds = THREE.ImageUtils.parseDDS( buffer, true ); + + texture.format = dds.format; + + texture.mipmaps = dds.mipmaps; + texture.image.width = dds.width; + texture.image.height = dds.height; + + // gl.generateMipmap fails for compressed textures + // mipmaps must be embedded in the DDS file + // or texture filters must not use mipmapping + + texture.generateMipmaps = false; + + texture.needsUpdate = true; + + if ( onLoad ) onLoad( texture ); + + } + + request.onerror = onError; + + request.open( 'GET', url, true ); + request.responseType = "arraybuffer"; + request.send( null ); + + return texture; + + }, + + loadTextureCube: function ( array, mapping, onLoad, onError ) { + + var images = []; + images.loadCount = 0; + + var texture = new THREE.Texture(); + texture.image = images; + if ( mapping !== undefined ) texture.mapping = mapping; + + // no flipping needed for cube textures + + texture.flipY = false; + + for ( var i = 0, il = array.length; i < il; ++ i ) { + + var cubeImage = new Image(); + images[ i ] = cubeImage; + + cubeImage.onload = function () { + + images.loadCount += 1; + + if ( images.loadCount === 6 ) { + + texture.needsUpdate = true; + if ( onLoad ) onLoad( texture ); + + } + + }; + + cubeImage.onerror = onError; + + cubeImage.crossOrigin = this.crossOrigin; + cubeImage.src = array[ i ]; + + } + + return texture; + + }, + + loadCompressedTextureCube: function ( array, mapping, onLoad, onError ) { + + var images = []; + images.loadCount = 0; + + var texture = new THREE.CompressedTexture(); + texture.image = images; + if ( mapping !== undefined ) texture.mapping = mapping; + + // no flipping for cube textures + // (also flipping doesn't work for compressed textures ) + + texture.flipY = false; + + // can't generate mipmaps for compressed textures + // mips must be embedded in DDS files + + texture.generateMipmaps = false; + + var generateCubeFaceCallback = function ( rq, img ) { + + return function () { + + var buffer = rq.response; + var dds = THREE.ImageUtils.parseDDS( buffer, true ); + + img.format = dds.format; + + img.mipmaps = dds.mipmaps; + img.width = dds.width; + img.height = dds.height; + + images.loadCount += 1; + + if ( images.loadCount === 6 ) { + + texture.format = dds.format; + texture.needsUpdate = true; + if ( onLoad ) onLoad( texture ); + + } + + } + + } + + // compressed cubemap textures as 6 separate DDS files + + if ( array instanceof Array ) { + + for ( var i = 0, il = array.length; i < il; ++ i ) { + + var cubeImage = {}; + images[ i ] = cubeImage; + + var request = new XMLHttpRequest(); + + request.onload = generateCubeFaceCallback( request, cubeImage ); + request.onerror = onError; + + var url = array[ i ]; + + request.open( 'GET', url, true ); + request.responseType = "arraybuffer"; + request.send( null ); + + } + + // compressed cubemap texture stored in a single DDS file + + } else { + + var url = array; + var request = new XMLHttpRequest(); + + request.onload = function( ) { + + var buffer = request.response; + var dds = THREE.ImageUtils.parseDDS( buffer, true ); + + if ( dds.isCubemap ) { + + var faces = dds.mipmaps.length / dds.mipmapCount; + + for ( var f = 0; f < faces; f ++ ) { + + images[ f ] = { mipmaps : [] }; + + for ( var i = 0; i < dds.mipmapCount; i ++ ) { + + images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] ); + images[ f ].format = dds.format; + images[ f ].width = dds.width; + images[ f ].height = dds.height; + + } + + } + + texture.format = dds.format; + texture.needsUpdate = true; + if ( onLoad ) onLoad( texture ); + + } + + } + + request.onerror = onError; + + request.open( 'GET', url, true ); + request.responseType = "arraybuffer"; + request.send( null ); + + } + + return texture; + + }, + + loadDDSTexture: function ( url, mapping, onLoad, onError ) { + + var images = []; + images.loadCount = 0; + + var texture = new THREE.CompressedTexture(); + texture.image = images; + if ( mapping !== undefined ) texture.mapping = mapping; + + // no flipping for cube textures + // (also flipping doesn't work for compressed textures ) + + texture.flipY = false; + + // can't generate mipmaps for compressed textures + // mips must be embedded in DDS files + + texture.generateMipmaps = false; + + { + var request = new XMLHttpRequest(); + + request.onload = function( ) { + + var buffer = request.response; + var dds = THREE.ImageUtils.parseDDS( buffer, true ); + + if ( dds.isCubemap ) { + + var faces = dds.mipmaps.length / dds.mipmapCount; + + for ( var f = 0; f < faces; f ++ ) { + + images[ f ] = { mipmaps : [] }; + + for ( var i = 0; i < dds.mipmapCount; i ++ ) { + + images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] ); + images[ f ].format = dds.format; + images[ f ].width = dds.width; + images[ f ].height = dds.height; + + } + + } + + + } else { + texture.image.width = dds.width; + texture.image.height = dds.height; + texture.mipmaps = dds.mipmaps; + } + + texture.format = dds.format; + texture.needsUpdate = true; + if ( onLoad ) onLoad( texture ); + + } + + request.onerror = onError; + + request.open( 'GET', url, true ); + request.responseType = "arraybuffer"; + request.send( null ); + + } + + return texture; + + }, + + parseDDS: function ( buffer, loadMipmaps ) { + + var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 }; + + // Adapted from @toji's DDS utils + // https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js + + // All values and structures referenced from: + // http://msdn.microsoft.com/en-us/library/bb943991.aspx/ + + var DDS_MAGIC = 0x20534444; + + var DDSD_CAPS = 0x1, + DDSD_HEIGHT = 0x2, + DDSD_WIDTH = 0x4, + DDSD_PITCH = 0x8, + DDSD_PIXELFORMAT = 0x1000, + DDSD_MIPMAPCOUNT = 0x20000, + DDSD_LINEARSIZE = 0x80000, + DDSD_DEPTH = 0x800000; + + var DDSCAPS_COMPLEX = 0x8, + DDSCAPS_MIPMAP = 0x400000, + DDSCAPS_TEXTURE = 0x1000; + + var DDSCAPS2_CUBEMAP = 0x200, + DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, + DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, + DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, + DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, + DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, + DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, + DDSCAPS2_VOLUME = 0x200000; + + var DDPF_ALPHAPIXELS = 0x1, + DDPF_ALPHA = 0x2, + DDPF_FOURCC = 0x4, + DDPF_RGB = 0x40, + DDPF_YUV = 0x200, + DDPF_LUMINANCE = 0x20000; + + function fourCCToInt32( value ) { + + return value.charCodeAt(0) + + (value.charCodeAt(1) << 8) + + (value.charCodeAt(2) << 16) + + (value.charCodeAt(3) << 24); + + } + + function int32ToFourCC( value ) { + + return String.fromCharCode( + value & 0xff, + (value >> 8) & 0xff, + (value >> 16) & 0xff, + (value >> 24) & 0xff + ); + } + + function loadARGBMip( buffer, dataOffset, width, height ) { + var dataLength = width*height*4; + var srcBuffer = new Uint8Array( buffer, dataOffset, dataLength ); + var byteArray = new Uint8Array( dataLength ); + var dst = 0; + var src = 0; + for ( var y = 0; y < height; y++ ) { + for ( var x = 0; x < width; x++ ) { + var b = srcBuffer[src]; src++; + var g = srcBuffer[src]; src++; + var r = srcBuffer[src]; src++; + var a = srcBuffer[src]; src++; + byteArray[dst] = r; dst++; //r + byteArray[dst] = g; dst++; //g + byteArray[dst] = b; dst++; //b + byteArray[dst] = a; dst++; //a + } + } + return byteArray; + } + + var FOURCC_DXT1 = fourCCToInt32("DXT1"); + var FOURCC_DXT3 = fourCCToInt32("DXT3"); + var FOURCC_DXT5 = fourCCToInt32("DXT5"); + + var headerLengthInt = 31; // The header length in 32 bit ints + + // Offsets into the header array + + var off_magic = 0; + + var off_size = 1; + var off_flags = 2; + var off_height = 3; + var off_width = 4; + + var off_mipmapCount = 7; + + var off_pfFlags = 20; + var off_pfFourCC = 21; + var off_RGBBitCount = 22; + var off_RBitMask = 23; + var off_GBitMask = 24; + var off_BBitMask = 25; + var off_ABitMask = 26; + + var off_caps = 27; + var off_caps2 = 28; + var off_caps3 = 29; + var off_caps4 = 30; + + // Parse header + + var header = new Int32Array( buffer, 0, headerLengthInt ); + + if ( header[ off_magic ] !== DDS_MAGIC ) { + + THREE.onerror( "ImageUtils.parseDDS(): Invalid magic number in DDS header" ); + return dds; + + } + + if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) { + + THREE.onerror( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" ); + return dds; + + } + + var blockBytes; + + var fourCC = header[ off_pfFourCC ]; + + var isRGBAUncompressed = false; + + switch ( fourCC ) { + + case FOURCC_DXT1: + + blockBytes = 8; + dds.format = THREE.RGB_S3TC_DXT1_Format; + break; + + case FOURCC_DXT3: + + blockBytes = 16; + dds.format = THREE.RGBA_S3TC_DXT3_Format; + break; + + case FOURCC_DXT5: + + blockBytes = 16; + dds.format = THREE.RGBA_S3TC_DXT5_Format; + break; + + default: + + if( header[off_RGBBitCount] ==32 + && header[off_RBitMask]&0xff0000 + && header[off_GBitMask]&0xff00 + && header[off_BBitMask]&0xff + && header[off_ABitMask]&0xff000000 ) { + isRGBAUncompressed = true; + blockBytes = 64; + dds.format = THREE.RGBAFormat; + } else { + THREE.onerror( "ImageUtils.parseDDS(): Unsupported FourCC code: ", int32ToFourCC( fourCC ) ); + return dds; + } + } + + dds.mipmapCount = 1; + + if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) { + + dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] ); + + } + + //TODO: Verify that all faces of the cubemap are present with DDSCAPS2_CUBEMAP_POSITIVEX, etc. + + dds.isCubemap = header[ off_caps2 ] & DDSCAPS2_CUBEMAP ? true : false; + + dds.width = header[ off_width ]; + dds.height = header[ off_height ]; + + var dataOffset = header[ off_size ] + 4; + + // Extract mipmaps buffers + + var width = dds.width; + var height = dds.height; + + var faces = dds.isCubemap ? 6 : 1; + + for ( var face = 0; face < faces; face ++ ) { + + for ( var i = 0; i < dds.mipmapCount; i ++ ) { + + if( isRGBAUncompressed ) { + var byteArray = loadARGBMip( buffer, dataOffset, width, height ); + var dataLength = byteArray.length; + } else { + var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes; + var byteArray = new Uint8Array( buffer, dataOffset, dataLength ); + } + + var mipmap = { "data": byteArray, "width": width, "height": height }; + dds.mipmaps.push( mipmap ); + + dataOffset += dataLength; + + width = Math.max( width * 0.5, 1 ); + height = Math.max( height * 0.5, 1 ); + + } + + width = dds.width; + height = dds.height; + + } + + return dds; + + }, + + getNormalMap: function ( image, depth ) { + + // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/ + + var cross = function ( a, b ) { + + return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ]; + + } + + var subtract = function ( a, b ) { + + return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ]; + + } + + var normalize = function ( a ) { + + var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] ); + return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ]; + + } + + depth = depth | 1; + + var width = image.width; + var height = image.height; + + var canvas = document.createElement( 'canvas' ); + canvas.width = width; + canvas.height = height; + + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0 ); + + var data = context.getImageData( 0, 0, width, height ).data; + var imageData = context.createImageData( width, height ); + var output = imageData.data; + + for ( var x = 0; x < width; x ++ ) { + + for ( var y = 0; y < height; y ++ ) { + + var ly = y - 1 < 0 ? 0 : y - 1; + var uy = y + 1 > height - 1 ? height - 1 : y + 1; + var lx = x - 1 < 0 ? 0 : x - 1; + var ux = x + 1 > width - 1 ? width - 1 : x + 1; + + var points = []; + var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ]; + points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] ); + points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] ); + points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] ); + points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] ); + points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] ); + points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] ); + + var normals = []; + var num_points = points.length; + + for ( var i = 0; i < num_points; i ++ ) { + + var v1 = points[ i ]; + var v2 = points[ ( i + 1 ) % num_points ]; + v1 = subtract( v1, origin ); + v2 = subtract( v2, origin ); + normals.push( normalize( cross( v1, v2 ) ) ); + + } + + var normal = [ 0, 0, 0 ]; + + for ( var i = 0; i < normals.length; i ++ ) { + + normal[ 0 ] += normals[ i ][ 0 ]; + normal[ 1 ] += normals[ i ][ 1 ]; + normal[ 2 ] += normals[ i ][ 2 ]; + + } + + normal[ 0 ] /= normals.length; + normal[ 1 ] /= normals.length; + normal[ 2 ] /= normals.length; + + var idx = ( y * width + x ) * 4; + + output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0; + output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0; + output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0; + output[ idx + 3 ] = 255; + + } + + } + + context.putImageData( imageData, 0, 0 ); + + return canvas; + + }, + + generateDataTexture: function ( width, height, color ) { + + var size = width * height; + var data = new Uint8Array( 3 * size ); + + var r = Math.floor( color.r * 255 ); + var g = Math.floor( color.g * 255 ); + var b = Math.floor( color.b * 255 ); + + for ( var i = 0; i < size; i ++ ) { + + data[ i * 3 ] = r; + data[ i * 3 + 1 ] = g; + data[ i * 3 + 2 ] = b; + + } + + var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat ); + texture.needsUpdate = true; + + return texture; + + } + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SceneUtils = { + + createMultiMaterialObject: function ( geometry, materials ) { + + var group = new THREE.Object3D(); + + for ( var i = 0, l = materials.length; i < l; i ++ ) { + + group.add( new THREE.Mesh( geometry, materials[ i ] ) ); + + } + + return group; + + }, + + detach : function ( child, parent, scene ) { + + child.applyMatrix( parent.matrixWorld ); + parent.remove( child ); + scene.add( child ); + + }, + + attach: function ( child, scene, parent ) { + + var matrixWorldInverse = new THREE.Matrix4(); + matrixWorldInverse.getInverse( parent.matrixWorld ); + child.applyMatrix( matrixWorldInverse ); + + scene.remove( child ); + parent.add( child ); + + } + +}; + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author alteredq / http://alteredqualia.com/ + * + * For Text operations in three.js (See TextGeometry) + * + * It uses techniques used in: + * + * typeface.js and canvastext + * For converting fonts and rendering with javascript + * http://typeface.neocracy.org + * + * Triangulation ported from AS3 + * Simple Polygon Triangulation + * http://actionsnippet.com/?p=1462 + * + * A Method to triangulate shapes with holes + * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/ + * + */ + +THREE.FontUtils = { + + faces : {}, + + // Just for now. face[weight][style] + + face : "helvetiker", + weight: "normal", + style : "normal", + size : 150, + divisions : 10, + + getFace : function() { + + return this.faces[ this.face ][ this.weight ][ this.style ]; + + }, + + loadFace : function( data ) { + + var family = data.familyName.toLowerCase(); + + var ThreeFont = this; + + ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {}; + + ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {}; + ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; + + var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; + + return data; + + }, + + drawText : function( text ) { + + var characterPts = [], allPts = []; + + // RenderText + + var i, p, + face = this.getFace(), + scale = this.size / face.resolution, + offset = 0, + chars = String( text ).split( '' ), + length = chars.length; + + var fontPaths = []; + + for ( i = 0; i < length; i ++ ) { + + var path = new THREE.Path(); + + var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path ); + offset += ret.offset; + + fontPaths.push( ret.path ); + + } + + // get the width + + var width = offset / 2; + // + // for ( p = 0; p < allPts.length; p++ ) { + // + // allPts[ p ].x -= width; + // + // } + + //var extract = this.extractPoints( allPts, characterPts ); + //extract.contour = allPts; + + //extract.paths = fontPaths; + //extract.offset = width; + + return { paths : fontPaths, offset : width }; + + }, + + + + + extractGlyphPoints : function( c, face, scale, offset, path ) { + + var pts = []; + + var i, i2, divisions, + outline, action, length, + scaleX, scaleY, + x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, + laste, + glyph = face.glyphs[ c ] || face.glyphs[ '?' ]; + + if ( !glyph ) return; + + if ( glyph.o ) { + + outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); + length = outline.length; + + scaleX = scale; + scaleY = scale; + + for ( i = 0; i < length; ) { + + action = outline[ i ++ ]; + + //console.log( action ); + + switch( action ) { + + case 'm': + + // Move To + + x = outline[ i++ ] * scaleX + offset; + y = outline[ i++ ] * scaleY; + + path.moveTo( x, y ); + break; + + case 'l': + + // Line To + + x = outline[ i++ ] * scaleX + offset; + y = outline[ i++ ] * scaleY; + path.lineTo(x,y); + break; + + case 'q': + + // QuadraticCurveTo + + cpx = outline[ i++ ] * scaleX + offset; + cpy = outline[ i++ ] * scaleY; + cpx1 = outline[ i++ ] * scaleX + offset; + cpy1 = outline[ i++ ] * scaleY; + + path.quadraticCurveTo(cpx1, cpy1, cpx, cpy); + + laste = pts[ pts.length - 1 ]; + + if ( laste ) { + + cpx0 = laste.x; + cpy0 = laste.y; + + for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { + + var t = i2 / divisions; + var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); + } + + } + + break; + + case 'b': + + // Cubic Bezier Curve + + cpx = outline[ i++ ] * scaleX + offset; + cpy = outline[ i++ ] * scaleY; + cpx1 = outline[ i++ ] * scaleX + offset; + cpy1 = outline[ i++ ] * -scaleY; + cpx2 = outline[ i++ ] * scaleX + offset; + cpy2 = outline[ i++ ] * -scaleY; + + path.bezierCurveTo( cpx, cpy, cpx1, cpy1, cpx2, cpy2 ); + + laste = pts[ pts.length - 1 ]; + + if ( laste ) { + + cpx0 = laste.x; + cpy0 = laste.y; + + for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { + + var t = i2 / divisions; + var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); + var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); + + } + + } + + break; + + } + + } + } + + + + return { offset: glyph.ha*scale, path:path}; + } + +}; + + +THREE.FontUtils.generateShapes = function( text, parameters ) { + + // Parameters + + parameters = parameters || {}; + + var size = parameters.size !== undefined ? parameters.size : 100; + var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4; + + var font = parameters.font !== undefined ? parameters.font : "helvetiker"; + var weight = parameters.weight !== undefined ? parameters.weight : "normal"; + var style = parameters.style !== undefined ? parameters.style : "normal"; + + THREE.FontUtils.size = size; + THREE.FontUtils.divisions = curveSegments; + + THREE.FontUtils.face = font; + THREE.FontUtils.weight = weight; + THREE.FontUtils.style = style; + + // Get a Font data json object + + var data = THREE.FontUtils.drawText( text ); + + var paths = data.paths; + var shapes = []; + + for ( var p = 0, pl = paths.length; p < pl; p ++ ) { + + Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); + + } + + return shapes; + +}; + + +/** + * This code is a quick port of code written in C++ which was submitted to + * flipcode.com by John W. Ratcliff // July 22, 2000 + * See original code and more information here: + * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml + * + * ported to actionscript by Zevan Rosser + * www.actionsnippet.com + * + * ported to javascript by Joshua Koo + * http://www.lab4games.net/zz85/blog + * + */ + + +( function( namespace ) { + + var EPSILON = 0.0000000001; + + // takes in an contour array and returns + + var process = function( contour, indices ) { + + var n = contour.length; + + if ( n < 3 ) return null; + + var result = [], + verts = [], + vertIndices = []; + + /* we want a counter-clockwise polygon in verts */ + + var u, v, w; + + if ( area( contour ) > 0.0 ) { + + for ( v = 0; v < n; v++ ) verts[ v ] = v; + + } else { + + for ( v = 0; v < n; v++ ) verts[ v ] = ( n - 1 ) - v; + + } + + var nv = n; + + /* remove nv - 2 vertices, creating 1 triangle every time */ + + var count = 2 * nv; /* error detection */ + + for( v = nv - 1; nv > 2; ) { + + /* if we loop, it is probably a non-simple polygon */ + + if ( ( count-- ) <= 0 ) { + + //** Triangulate: ERROR - probable bad polygon! + + // Sometimes warning is fine, especially polygons are triangulated in reverse. + THREE.onwarning( "Warning, unable to triangulate polygon!" ); + + if ( indices ) return vertIndices; + return result; + + } + + /* three consecutive vertices in current polygon, */ + + u = v; if ( nv <= u ) u = 0; /* previous */ + v = u + 1; if ( nv <= v ) v = 0; /* new v */ + w = v + 1; if ( nv <= w ) w = 0; /* next */ + + if ( snip( contour, u, v, w, nv, verts ) ) { + + var a, b, c, s, t; + + /* true names of the vertices */ + + a = verts[ u ]; + b = verts[ v ]; + c = verts[ w ]; + + /* output Triangle */ + + result.push( [ contour[ a ], + contour[ b ], + contour[ c ] ] ); + + + vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] ); + + /* remove v from the remaining polygon */ + + for( s = v, t = v + 1; t < nv; s++, t++ ) { + + verts[ s ] = verts[ t ]; + + } + + nv--; + + /* reset error detection counter */ + + count = 2 * nv; + + } + + } + + if ( indices ) return vertIndices; + return result; + + }; + + // calculate area of the contour polygon + + var area = function ( contour ) { + + var n = contour.length; + var a = 0.0; + + for( var p = n - 1, q = 0; q < n; p = q++ ) { + + a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; + + } + + return a * 0.5; + + }; + + var snip = function ( contour, u, v, w, n, verts ) { + + var p; + var ax, ay, bx, by; + var cx, cy, px, py; + + ax = contour[ verts[ u ] ].x; + ay = contour[ verts[ u ] ].y; + + bx = contour[ verts[ v ] ].x; + by = contour[ verts[ v ] ].y; + + cx = contour[ verts[ w ] ].x; + cy = contour[ verts[ w ] ].y; + + if ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false; + + var aX, aY, bX, bY, cX, cY; + var apx, apy, bpx, bpy, cpx, cpy; + var cCROSSap, bCROSScp, aCROSSbp; + + aX = cx - bx; aY = cy - by; + bX = ax - cx; bY = ay - cy; + cX = bx - ax; cY = by - ay; + + for ( p = 0; p < n; p++ ) { + + px = contour[ verts[ p ] ].x + py = contour[ verts[ p ] ].y + + if ( ( (px === ax) && (py === ay) ) || + ( (px === bx) && (py === by) ) || + ( (px === cx) && (py === cy) ) ) continue; + + apx = px - ax; apy = py - ay; + bpx = px - bx; bpy = py - by; + cpx = px - cx; cpy = py - cy; + + // see if p is inside triangle abc + + aCROSSbp = aX*bpy - aY*bpx; + cCROSSap = cX*apy - cY*apx; + bCROSScp = bX*cpy - bY*cpx; + + if ( (aCROSSbp >= -EPSILON) && (bCROSScp >= -EPSILON) && (cCROSSap >= -EPSILON) ) return false; + + } + + return true; + + }; + + + namespace.Triangulate = process; + namespace.Triangulate.area = area; + + return namespace; + +})(THREE.FontUtils); + +// To use the typeface.js face files, hook up the API +self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace }; +THREE.typeface_js = self._typeface_js; + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Extensible curve object + * + * Some common of Curve methods + * .getPoint(t), getTangent(t) + * .getPointAt(u), getTagentAt(u) + * .getPoints(), .getSpacedPoints() + * .getLength() + * .updateArcLengths() + * + * This following classes subclasses THREE.Curve: + * + * -- 2d classes -- + * THREE.LineCurve + * THREE.QuadraticBezierCurve + * THREE.CubicBezierCurve + * THREE.SplineCurve + * THREE.ArcCurve + * THREE.EllipseCurve + * + * -- 3d classes -- + * THREE.LineCurve3 + * THREE.QuadraticBezierCurve3 + * THREE.CubicBezierCurve3 + * THREE.SplineCurve3 + * THREE.ClosedSplineCurve3 + * + * A series of curves can be represented as a THREE.CurvePath + * + **/ + +/************************************************************** + * Abstract Curve base class + **************************************************************/ + +THREE.Curve = function () { + +}; + +// Virtual base class method to overwrite and implement in subclasses +// - t [0 .. 1] + +THREE.Curve.prototype.getPoint = function ( t ) { + + THREE.onwarning( "Warning, getPoint() not implemented!" ); + return null; + +}; + +// Get point at relative position in curve according to arc length +// - u [0 .. 1] + +THREE.Curve.prototype.getPointAt = function ( u ) { + + var t = this.getUtoTmapping( u ); + return this.getPoint( t ); + +}; + +// Get sequence of points using getPoint( t ) + +THREE.Curve.prototype.getPoints = function ( divisions ) { + + if ( !divisions ) divisions = 5; + + var d, pts = []; + + for ( d = 0; d <= divisions; d ++ ) { + + pts.push( this.getPoint( d / divisions ) ); + + } + + return pts; + +}; + +// Get sequence of points using getPointAt( u ) + +THREE.Curve.prototype.getSpacedPoints = function ( divisions ) { + + if ( !divisions ) divisions = 5; + + var d, pts = []; + + for ( d = 0; d <= divisions; d ++ ) { + + pts.push( this.getPointAt( d / divisions ) ); + + } + + return pts; + +}; + +// Get total curve arc length + +THREE.Curve.prototype.getLength = function () { + + var lengths = this.getLengths(); + return lengths[ lengths.length - 1 ]; + +}; + +// Get list of cumulative segment lengths + +THREE.Curve.prototype.getLengths = function ( divisions ) { + + if ( !divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200; + + if ( this.cacheArcLengths + && ( this.cacheArcLengths.length == divisions + 1 ) + && !this.needsUpdate) { + + //console.log( "cached", this.cacheArcLengths ); + return this.cacheArcLengths; + + } + + this.needsUpdate = false; + + var cache = []; + var current, last = this.getPoint( 0 ); + var p, sum = 0; + + cache.push( 0 ); + + for ( p = 1; p <= divisions; p ++ ) { + + current = this.getPoint ( p / divisions ); + sum += current.distanceTo( last ); + cache.push( sum ); + last = current; + + } + + this.cacheArcLengths = cache; + + return cache; // { sums: cache, sum:sum }; Sum is in the last element. + +}; + + +THREE.Curve.prototype.updateArcLengths = function() { + this.needsUpdate = true; + this.getLengths(); +}; + +// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance + +THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) { + + var arcLengths = this.getLengths(); + + var i = 0, il = arcLengths.length; + + var targetArcLength; // The targeted u distance value to get + + if ( distance ) { + + targetArcLength = distance; + + } else { + + targetArcLength = u * arcLengths[ il - 1 ]; + + } + + //var time = Date.now(); + + // binary search for the index with largest value smaller than target u distance + + var low = 0, high = il - 1, comparison; + + while ( low <= high ) { + + 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 + + comparison = arcLengths[ i ] - targetArcLength; + + if ( comparison < 0 ) { + + low = i + 1; + continue; + + } else if ( comparison > 0 ) { + + high = i - 1; + continue; + + } else { + + high = i; + break; + + // DONE + + } + + } + + i = high; + + //console.log('b' , i, low, high, Date.now()- time); + + if ( arcLengths[ i ] == targetArcLength ) { + + var t = i / ( il - 1 ); + return t; + + } + + // we could get finer grain at lengths, or use simple interpolatation between two points + + var lengthBefore = arcLengths[ i ]; + var lengthAfter = arcLengths[ i + 1 ]; + + var segmentLength = lengthAfter - lengthBefore; + + // determine where we are between the 'before' and 'after' points + + var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + + // add that fractional amount to t + + var t = ( i + segmentFraction ) / ( il -1 ); + + return t; + +}; + +// Returns a unit vector tangent at t +// In case any sub curve does not implement its tangent derivation, +// 2 points a small delta apart will be used to find its gradient +// which seems to give a reasonable approximation + +THREE.Curve.prototype.getTangent = function( t ) { + + var delta = 0.0001; + var t1 = t - delta; + var t2 = t + delta; + + // Capping in case of danger + + if ( t1 < 0 ) t1 = 0; + if ( t2 > 1 ) t2 = 1; + + var pt1 = this.getPoint( t1 ); + var pt2 = this.getPoint( t2 ); + + var vec = pt2.clone().sub(pt1); + return vec.normalize(); + +}; + + +THREE.Curve.prototype.getTangentAt = function ( u ) { + + var t = this.getUtoTmapping( u ); + return this.getTangent( t ); + +}; + + + + + +/************************************************************** + * Utils + **************************************************************/ + +THREE.Curve.Utils = { + + tangentQuadraticBezier: function ( t, p0, p1, p2 ) { + + return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ); + + }, + + // Puay Bing, thanks for helping with this derivative! + + tangentCubicBezier: function (t, p0, p1, p2, p3 ) { + + return -3 * p0 * (1 - t) * (1 - t) + + 3 * p1 * (1 - t) * (1-t) - 6 *t *p1 * (1-t) + + 6 * t * p2 * (1-t) - 3 * t * t * p2 + + 3 * t * t * p3; + }, + + + tangentSpline: function ( t, p0, p1, p2, p3 ) { + + // To check if my formulas are correct + + var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1 + var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t + var h01 = -6 * t * t + 6 * t; // − 2t3 + 3t2 + var h11 = 3 * t * t - 2 * t; // t3 − t2 + + return h00 + h10 + h01 + h11; + + }, + + // Catmull-Rom + + interpolate: function( p0, p1, p2, p3, t ) { + + var v0 = ( p2 - p0 ) * 0.5; + var v1 = ( p3 - p1 ) * 0.5; + var t2 = t * t; + var t3 = t * t2; + return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; + + } + +}; + + +// TODO: Transformation for Curves? + +/************************************************************** + * 3D Curves + **************************************************************/ + +// A Factory method for creating new curve subclasses + +THREE.Curve.create = function ( constructor, getPointFunc ) { + + constructor.prototype = Object.create( THREE.Curve.prototype ); + constructor.prototype.getPoint = getPointFunc; + + return constructor; + +}; + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * + **/ + +/************************************************************** + * Curved Path - a curve path is simply a array of connected + * curves, but retains the api of a curve + **************************************************************/ + +THREE.CurvePath = function () { + + this.curves = []; + this.bends = []; + + this.autoClose = false; // Automatically closes the path +}; + +THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype ); + +THREE.CurvePath.prototype.add = function ( curve ) { + + this.curves.push( curve ); + +}; + +THREE.CurvePath.prototype.checkConnection = function() { + // TODO + // If the ending of curve is not connected to the starting + // or the next curve, then, this is not a real path +}; + +THREE.CurvePath.prototype.closePath = function() { + // TODO Test + // and verify for vector3 (needs to implement equals) + // Add a line curve if start and end of lines are not connected + var startPoint = this.curves[0].getPoint(0); + var endPoint = this.curves[this.curves.length-1].getPoint(1); + + if (!startPoint.equals(endPoint)) { + this.curves.push( new THREE.LineCurve(endPoint, startPoint) ); + } + +}; + +// To get accurate point with reference to +// entire path distance at time t, +// following has to be done: + +// 1. Length of each sub path have to be known +// 2. Locate and identify type of curve +// 3. Get t for the curve +// 4. Return curve.getPointAt(t') + +THREE.CurvePath.prototype.getPoint = function( t ) { + + var d = t * this.getLength(); + var curveLengths = this.getCurveLengths(); + var i = 0, diff, curve; + + // To think about boundaries points. + + while ( i < curveLengths.length ) { + + if ( curveLengths[ i ] >= d ) { + + diff = curveLengths[ i ] - d; + curve = this.curves[ i ]; + + var u = 1 - diff / curve.getLength(); + + return curve.getPointAt( u ); + + break; + } + + i ++; + + } + + return null; + + // loop where sum != 0, sum > d , sum+1 maxX ) maxX = p.x; + else if ( p.x < minX ) minX = p.x; + + if ( p.y > maxY ) maxY = p.y; + else if ( p.y < minY ) minY = p.y; + + if ( v3 ) { + + if ( p.z > maxZ ) maxZ = p.z; + else if ( p.z < minZ ) minZ = p.z; + + } + + sum.add( p ); + + } + + var ret = { + + minX: minX, + minY: minY, + maxX: maxX, + maxY: maxY, + centroid: sum.divideScalar( il ) + + }; + + if ( v3 ) { + + ret.maxZ = maxZ; + ret.minZ = minZ; + + } + + return ret; + +}; + +/************************************************************** + * Create Geometries Helpers + **************************************************************/ + +/// Generate geometry from path points (for Line or ParticleSystem objects) + +THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) { + + var pts = this.getPoints( divisions, true ); + return this.createGeometry( pts ); + +}; + +// Generate geometry from equidistance sampling along the path + +THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) { + + var pts = this.getSpacedPoints( divisions, true ); + return this.createGeometry( pts ); + +}; + +THREE.CurvePath.prototype.createGeometry = function( points ) { + + var geometry = new THREE.Geometry(); + + for ( var i = 0; i < points.length; i ++ ) { + + geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) ); + + } + + return geometry; + +}; + + +/************************************************************** + * Bend / Wrap Helper Methods + **************************************************************/ + +// Wrap path / Bend modifiers? + +THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) { + + this.bends.push( bendpath ); + +}; + +THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) { + + var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints + var i, il; + + if ( !bends ) { + + bends = this.bends; + + } + + for ( i = 0, il = bends.length; i < il; i ++ ) { + + oldPts = this.getWrapPoints( oldPts, bends[ i ] ); + + } + + return oldPts; + +}; + +THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) { + + var oldPts = this.getSpacedPoints( segments ); + + var i, il; + + if ( !bends ) { + + bends = this.bends; + + } + + for ( i = 0, il = bends.length; i < il; i ++ ) { + + oldPts = this.getWrapPoints( oldPts, bends[ i ] ); + + } + + return oldPts; + +}; + +// This returns getPoints() bend/wrapped around the contour of a path. +// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html + +THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) { + + var bounds = this.getBoundingBox(); + + var i, il, p, oldX, oldY, xNorm; + + for ( i = 0, il = oldPts.length; i < il; i ++ ) { + + p = oldPts[ i ]; + + oldX = p.x; + oldY = p.y; + + xNorm = oldX / bounds.maxX; + + // If using actual distance, for length > path, requires line extrusions + //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance + + xNorm = path.getUtoTmapping( xNorm, oldX ); + + // check for out of bounds? + + var pathPt = path.getPoint( xNorm ); + var normal = path.getTangent( xNorm ); + normal.set( -normal.y, normal.x ).multiplyScalar( oldY ); + + p.x = pathPt.x + normal.x; + p.y = pathPt.y + normal.y; + + } + + return oldPts; + +}; + + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Gyroscope = function () { + + THREE.Object3D.call( this ); + +}; + +THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.Gyroscope.prototype.updateMatrixWorld = function ( force ) { + + this.matrixAutoUpdate && this.updateMatrix(); + + // update matrixWorld + + if ( this.matrixWorldNeedsUpdate || force ) { + + if ( this.parent ) { + + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + + this.matrixWorld.decompose( this.translationWorld, this.quaternionWorld, this.scaleWorld ); + this.matrix.decompose( this.translationObject, this.quaternionObject, this.scaleObject ); + + this.matrixWorld.compose( this.translationWorld, this.quaternionObject, this.scaleWorld ); + + + } else { + + this.matrixWorld.copy( this.matrix ); + + } + + + this.matrixWorldNeedsUpdate = false; + + force = true; + + } + + // update children + + for ( var i = 0, l = this.children.length; i < l; i ++ ) { + + this.children[ i ].updateMatrixWorld( force ); + + } + +}; + +THREE.Gyroscope.prototype.translationWorld = new THREE.Vector3(); +THREE.Gyroscope.prototype.translationObject = new THREE.Vector3(); +THREE.Gyroscope.prototype.quaternionWorld = new THREE.Quaternion(); +THREE.Gyroscope.prototype.quaternionObject = new THREE.Quaternion(); +THREE.Gyroscope.prototype.scaleWorld = new THREE.Vector3(); +THREE.Gyroscope.prototype.scaleObject = new THREE.Vector3(); + + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Creates free form 2d path using series of points, lines or curves. + * + **/ + +THREE.Path = function ( points ) { + + THREE.CurvePath.call(this); + + this.actions = []; + + if ( points ) { + + this.fromPoints( points ); + + } + +}; + +THREE.Path.prototype = Object.create( THREE.CurvePath.prototype ); + +THREE.PathActions = { + + MOVE_TO: 'moveTo', + LINE_TO: 'lineTo', + QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve + BEZIER_CURVE_TO: 'bezierCurveTo', // Bezier cubic curve + CSPLINE_THRU: 'splineThru', // Catmull-rom spline + ARC: 'arc', // Circle + ELLIPSE: 'ellipse' +}; + +// TODO Clean up PATH API + +// Create path using straight lines to connect all points +// - vectors: array of Vector2 + +THREE.Path.prototype.fromPoints = function ( vectors ) { + + this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); + + for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) { + + this.lineTo( vectors[ v ].x, vectors[ v ].y ); + + }; + +}; + +// startPath() endPath()? + +THREE.Path.prototype.moveTo = function ( x, y ) { + + var args = Array.prototype.slice.call( arguments ); + this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } ); + +}; + +THREE.Path.prototype.lineTo = function ( x, y ) { + + var args = Array.prototype.slice.call( arguments ); + + var lastargs = this.actions[ this.actions.length - 1 ].args; + + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) ); + this.curves.push( curve ); + + this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } ); + +}; + +THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) { + + var args = Array.prototype.slice.call( arguments ); + + var lastargs = this.actions[ this.actions.length - 1 ].args; + + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ), + new THREE.Vector2( aCPx, aCPy ), + new THREE.Vector2( aX, aY ) ); + this.curves.push( curve ); + + this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } ); + +}; + +THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, + aCP2x, aCP2y, + aX, aY ) { + + var args = Array.prototype.slice.call( arguments ); + + var lastargs = this.actions[ this.actions.length - 1 ].args; + + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ), + new THREE.Vector2( aCP1x, aCP1y ), + new THREE.Vector2( aCP2x, aCP2y ), + new THREE.Vector2( aX, aY ) ); + this.curves.push( curve ); + + this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } ); + +}; + +THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) { + + var args = Array.prototype.slice.call( arguments ); + var lastargs = this.actions[ this.actions.length - 1 ].args; + + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; +//--- + var npts = [ new THREE.Vector2( x0, y0 ) ]; + Array.prototype.push.apply( npts, pts ); + + var curve = new THREE.SplineCurve( npts ); + this.curves.push( curve ); + + this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } ); + +}; + +// FUTURE: Change the API or follow canvas API? + +THREE.Path.prototype.arc = function ( aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise ) { + + var lastargs = this.actions[ this.actions.length - 1].args; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + this.absarc(aX + x0, aY + y0, aRadius, + aStartAngle, aEndAngle, aClockwise ); + + }; + + THREE.Path.prototype.absarc = function ( aX, aY, aRadius, + aStartAngle, aEndAngle, aClockwise ) { + this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); + }; + +THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ) { + + var lastargs = this.actions[ this.actions.length - 1].args; + var x0 = lastargs[ lastargs.length - 2 ]; + var y0 = lastargs[ lastargs.length - 1 ]; + + this.absellipse(aX + x0, aY + y0, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ); + + }; + + +THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ) { + + var args = Array.prototype.slice.call( arguments ); + var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, + aStartAngle, aEndAngle, aClockwise ); + this.curves.push( curve ); + + var lastPoint = curve.getPoint(1); + args.push(lastPoint.x); + args.push(lastPoint.y); + + this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } ); + + }; + +THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) { + + if ( ! divisions ) divisions = 40; + + var points = []; + + for ( var i = 0; i < divisions; i ++ ) { + + points.push( this.getPoint( i / divisions ) ); + + //if( !this.getPoint( i / divisions ) ) throw "DIE"; + + } + + // if ( closedPath ) { + // + // points.push( points[ 0 ] ); + // + // } + + return points; + +}; + +/* Return an array of vectors based on contour of the path */ + +THREE.Path.prototype.getPoints = function( divisions, closedPath ) { + + if (this.useSpacedPoints) { + console.log('tata'); + return this.getSpacedPoints( divisions, closedPath ); + } + + divisions = divisions || 12; + + var points = []; + + var i, il, item, action, args; + var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, + laste, j, + t, tx, ty; + + for ( i = 0, il = this.actions.length; i < il; i ++ ) { + + item = this.actions[ i ]; + + action = item.action; + args = item.args; + + switch( action ) { + + case THREE.PathActions.MOVE_TO: + + points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); + + break; + + case THREE.PathActions.LINE_TO: + + points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); + + break; + + case THREE.PathActions.QUADRATIC_CURVE_TO: + + cpx = args[ 2 ]; + cpy = args[ 3 ]; + + cpx1 = args[ 0 ]; + cpy1 = args[ 1 ]; + + if ( points.length > 0 ) { + + laste = points[ points.length - 1 ]; + + cpx0 = laste.x; + cpy0 = laste.y; + + } else { + + laste = this.actions[ i - 1 ].args; + + cpx0 = laste[ laste.length - 2 ]; + cpy0 = laste[ laste.length - 1 ]; + + } + + for ( j = 1; j <= divisions; j ++ ) { + + t = j / divisions; + + tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); + + points.push( new THREE.Vector2( tx, ty ) ); + + } + + break; + + case THREE.PathActions.BEZIER_CURVE_TO: + + cpx = args[ 4 ]; + cpy = args[ 5 ]; + + cpx1 = args[ 0 ]; + cpy1 = args[ 1 ]; + + cpx2 = args[ 2 ]; + cpy2 = args[ 3 ]; + + if ( points.length > 0 ) { + + laste = points[ points.length - 1 ]; + + cpx0 = laste.x; + cpy0 = laste.y; + + } else { + + laste = this.actions[ i - 1 ].args; + + cpx0 = laste[ laste.length - 2 ]; + cpy0 = laste[ laste.length - 1 ]; + + } + + + for ( j = 1; j <= divisions; j ++ ) { + + t = j / divisions; + + tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); + ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); + + points.push( new THREE.Vector2( tx, ty ) ); + + } + + break; + + case THREE.PathActions.CSPLINE_THRU: + + laste = this.actions[ i - 1 ].args; + + var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); + var spts = [ last ]; + + var n = divisions * args[ 0 ].length; + + spts = spts.concat( args[ 0 ] ); + + var spline = new THREE.SplineCurve( spts ); + + for ( j = 1; j <= n; j ++ ) { + + points.push( spline.getPointAt( j / n ) ) ; + + } + + break; + + case THREE.PathActions.ARC: + + var aX = args[ 0 ], aY = args[ 1 ], + aRadius = args[ 2 ], + aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], + aClockwise = !!args[ 5 ]; + + var deltaAngle = aEndAngle - aStartAngle; + var angle; + var tdivisions = divisions * 2; + + for ( j = 1; j <= tdivisions; j ++ ) { + + t = j / tdivisions; + + if ( ! aClockwise ) { + + t = 1 - t; + + } + + angle = aStartAngle + t * deltaAngle; + + tx = aX + aRadius * Math.cos( angle ); + ty = aY + aRadius * Math.sin( angle ); + + //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); + + points.push( new THREE.Vector2( tx, ty ) ); + + } + + //console.log(points); + + break; + + case THREE.PathActions.ELLIPSE: + + var aX = args[ 0 ], aY = args[ 1 ], + xRadius = args[ 2 ], + yRadius = args[ 3 ], + aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], + aClockwise = !!args[ 6 ]; + + + var deltaAngle = aEndAngle - aStartAngle; + var angle; + var tdivisions = divisions * 2; + + for ( j = 1; j <= tdivisions; j ++ ) { + + t = j / tdivisions; + + if ( ! aClockwise ) { + + t = 1 - t; + + } + + angle = aStartAngle + t * deltaAngle; + + tx = aX + xRadius * Math.cos( angle ); + ty = aY + yRadius * Math.sin( angle ); + + //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); + + points.push( new THREE.Vector2( tx, ty ) ); + + } + + //console.log(points); + + break; + + } // end switch + + } + + + + // Normalize to remove the closing point by default. + var lastPoint = points[ points.length - 1]; + var EPSILON = 0.0000000001; + if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON && + Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON) + points.splice( points.length - 1, 1); + if ( closedPath ) { + + points.push( points[ 0 ] ); + + } + + return points; + +}; + +// Breaks path into shapes + +THREE.Path.prototype.toShapes = function( isCCW ) { + + function isPointInsidePolygon( inPt, inPolygon ) { + var EPSILON = 0.0000000001; + + var polyLen = inPolygon.length; + + // inPt on polygon contour => immediate success or + // toggling of inside/outside at every single! intersection point of an edge + // with the horizontal line through inPt, left of inPt + // not counting lowerY endpoints of edges and whole edges on that line + var inside = false; + for( var p = polyLen - 1, q = 0; q < polyLen; p = q++ ) { + var edgeLowPt = inPolygon[ p ]; + var edgeHighPt = inPolygon[ q ]; + + var edgeDx = edgeHighPt.x - edgeLowPt.x; + var edgeDy = edgeHighPt.y - edgeLowPt.y; + + if ( Math.abs(edgeDy) > EPSILON ) { // not parallel + if ( edgeDy < 0 ) { + edgeLowPt = inPolygon[ q ]; edgeDx = -edgeDx; + edgeHighPt = inPolygon[ p ]; edgeDy = -edgeDy; + } + if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; + + if ( inPt.y == edgeLowPt.y ) { + if ( inPt.x == edgeLowPt.x ) return true; // inPt is on contour ? + // continue; // no intersection or edgeLowPt => doesn't count !!! + } else { + var perpEdge = edgeDy * (inPt.x - edgeLowPt.x) - edgeDx * (inPt.y - edgeLowPt.y); + if ( perpEdge == 0 ) return true; // inPt is on contour ? + if ( perpEdge < 0 ) continue; + inside = !inside; // true intersection left of inPt + } + } else { // parallel or colinear + if ( inPt.y != edgeLowPt.y ) continue; // parallel + // egde lies on the same horizontal line as inPt + if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || + ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! + // continue; + } + } + + return inside; + } + + var i, il, item, action, args; + + var subPaths = [], lastPath = new THREE.Path(); + + for ( i = 0, il = this.actions.length; i < il; i ++ ) { + + item = this.actions[ i ]; + + args = item.args; + action = item.action; + + if ( action == THREE.PathActions.MOVE_TO ) { + + if ( lastPath.actions.length != 0 ) { + + subPaths.push( lastPath ); + lastPath = new THREE.Path(); + + } + + } + + lastPath[ action ].apply( lastPath, args ); + + } + + if ( lastPath.actions.length != 0 ) { + + subPaths.push( lastPath ); + + } + + // console.log(subPaths); + + if ( subPaths.length == 0 ) return []; + + var solid, tmpPath, tmpShape, shapes = []; + + if ( subPaths.length == 1) { + + tmpPath = subPaths[0]; + tmpShape = new THREE.Shape(); + tmpShape.actions = tmpPath.actions; + tmpShape.curves = tmpPath.curves; + shapes.push( tmpShape ); + return shapes; + + } + + var holesFirst = !THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() ); + holesFirst = isCCW ? !holesFirst : holesFirst; + + // console.log("Holes first", holesFirst); + + var betterShapeHoles = []; + var newShapes = []; + var newShapeHoles = []; + var mainIdx = 0; + var tmpPoints; + + newShapes[mainIdx] = undefined; + newShapeHoles[mainIdx] = []; + + for ( i = 0, il = subPaths.length; i < il; i ++ ) { + + tmpPath = subPaths[ i ]; + tmpPoints = tmpPath.getPoints(); + solid = THREE.Shape.Utils.isClockWise( tmpPoints ); + solid = isCCW ? !solid : solid; + + if ( solid ) { + + if ( (! holesFirst ) && ( newShapes[mainIdx] ) ) mainIdx++; + + newShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints }; + newShapes[mainIdx].s.actions = tmpPath.actions; + newShapes[mainIdx].s.curves = tmpPath.curves; + + if ( holesFirst ) mainIdx++; + newShapeHoles[mainIdx] = []; + + //console.log('cw', i); + + } else { + + newShapeHoles[mainIdx].push( { h: tmpPath, p: tmpPoints[0] } ); + + //console.log('ccw', i); + + } + + } + + if ( newShapes.length > 1 ) { + var ambigious = false; + var toChange = []; + + for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx++ ) { + betterShapeHoles[sIdx] = []; + } + for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx++ ) { + var sh = newShapes[sIdx]; + var sho = newShapeHoles[sIdx]; + for (var hIdx = 0; hIdx < sho.length; hIdx++ ) { + var ho = sho[hIdx]; + var hole_unassigned = true; + for (var s2Idx = 0; s2Idx < newShapes.length; s2Idx++ ) { + if ( isPointInsidePolygon( ho.p, newShapes[s2Idx].p ) ) { + if ( sIdx != s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } ); + if ( hole_unassigned ) { + hole_unassigned = false; + betterShapeHoles[s2Idx].push( ho ); + } else { + ambigious = true; + } + } + } + if ( hole_unassigned ) { betterShapeHoles[sIdx].push( ho ); } + } + } + // console.log("ambigious: ", ambigious); + if ( toChange.length > 0 ) { + // console.log("to change: ", toChange); + if (! ambigious) newShapeHoles = betterShapeHoles; + } + } + + var tmpHoles, j, jl; + for ( i = 0, il = newShapes.length; i < il; i ++ ) { + tmpShape = newShapes[i].s; + shapes.push( tmpShape ); + tmpHoles = newShapeHoles[i]; + for ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) { + tmpShape.holes.push( tmpHoles[j].h ); + } + } + + //console.log("shape", shapes); + + return shapes; + +}; + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Defines a 2d shape plane using paths. + **/ + +// STEP 1 Create a path. +// STEP 2 Turn path into shape. +// STEP 3 ExtrudeGeometry takes in Shape/Shapes +// STEP 3a - Extract points from each shape, turn to vertices +// STEP 3b - Triangulate each shape, add faces. + +THREE.Shape = function () { + + THREE.Path.apply( this, arguments ); + this.holes = []; + +}; + +THREE.Shape.prototype = Object.create( THREE.Path.prototype ); + +// Convenience method to return ExtrudeGeometry + +THREE.Shape.prototype.extrude = function ( options ) { + + var extruded = new THREE.ExtrudeGeometry( this, options ); + return extruded; + +}; + +// Convenience method to return ShapeGeometry + +THREE.Shape.prototype.makeGeometry = function ( options ) { + + var geometry = new THREE.ShapeGeometry( this, options ); + return geometry; + +}; + +// Get points of holes + +THREE.Shape.prototype.getPointsHoles = function ( divisions ) { + + var i, il = this.holes.length, holesPts = []; + + for ( i = 0; i < il; i ++ ) { + + holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends ); + + } + + return holesPts; + +}; + +// Get points of holes (spaced by regular distance) + +THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) { + + var i, il = this.holes.length, holesPts = []; + + for ( i = 0; i < il; i ++ ) { + + holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends ); + + } + + return holesPts; + +}; + + +// Get points of shape and holes (keypoints based on segments parameter) + +THREE.Shape.prototype.extractAllPoints = function ( divisions ) { + + return { + + shape: this.getTransformedPoints( divisions ), + holes: this.getPointsHoles( divisions ) + + }; + +}; + +THREE.Shape.prototype.extractPoints = function ( divisions ) { + + if (this.useSpacedPoints) { + return this.extractAllSpacedPoints(divisions); + } + + return this.extractAllPoints(divisions); + +}; + +// +// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) { +// +// return { +// +// shape: this.transform( bend, divisions ), +// holes: this.getPointsHoles( divisions, bend ) +// +// }; +// +// }; + +// Get points of shape and holes (spaced by regular distance) + +THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) { + + return { + + shape: this.getTransformedSpacedPoints( divisions ), + holes: this.getSpacedPointsHoles( divisions ) + + }; + +}; + +/************************************************************** + * Utils + **************************************************************/ + +THREE.Shape.Utils = { + + triangulateShape: function ( contour, holes ) { + + function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) { + // inOtherPt needs to be colinear to the inSegment + if ( inSegPt1.x != inSegPt2.x ) { + if ( inSegPt1.x < inSegPt2.x ) { + return ( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) ); + } else { + return ( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) ); + } + } else { + if ( inSegPt1.y < inSegPt2.y ) { + return ( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) ); + } else { + return ( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) ); + } + } + } + + function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) { + var EPSILON = 0.0000000001; + + var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y; + var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y; + + var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x; + var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y; + + var limit = seg1dy * seg2dx - seg1dx * seg2dy; + var perpSeg1 = seg1dy * seg1seg2dx - seg1dx * seg1seg2dy; + + if ( Math.abs(limit) > EPSILON ) { // not parallel + + var perpSeg2; + if ( limit > 0 ) { + if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) return []; + perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; + if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) return []; + } else { + if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) return []; + perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; + if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) return []; + } + + // i.e. to reduce rounding errors + // intersection at endpoint of segment#1? + if ( perpSeg2 == 0 ) { + if ( ( inExcludeAdjacentSegs ) && + ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return []; + return [ inSeg1Pt1 ]; + } + if ( perpSeg2 == limit ) { + if ( ( inExcludeAdjacentSegs ) && + ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return []; + return [ inSeg1Pt2 ]; + } + // intersection at endpoint of segment#2? + if ( perpSeg1 == 0 ) return [ inSeg2Pt1 ]; + if ( perpSeg1 == limit ) return [ inSeg2Pt2 ]; + + // return real intersection point + var factorSeg1 = perpSeg2 / limit; + return [ { x: inSeg1Pt1.x + factorSeg1 * seg1dx, + y: inSeg1Pt1.y + factorSeg1 * seg1dy } ]; + + } else { // parallel or colinear + if ( ( perpSeg1 != 0 ) || + ( seg2dy * seg1seg2dx != seg2dx * seg1seg2dy ) ) return []; + + // they are collinear or degenerate + var seg1Pt = ( (seg1dx == 0) && (seg1dy == 0) ); // segment1 ist just a point? + var seg2Pt = ( (seg2dx == 0) && (seg2dy == 0) ); // segment2 ist just a point? + // both segments are points + if ( seg1Pt && seg2Pt ) { + if ( (inSeg1Pt1.x != inSeg2Pt1.x) || + (inSeg1Pt1.y != inSeg2Pt1.y) ) return []; // they are distinct points + return [ inSeg1Pt1 ]; // they are the same point + } + // segment#1 is a single point + if ( seg1Pt ) { + if (! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) ) return []; // but not in segment#2 + return [ inSeg1Pt1 ]; + } + // segment#2 is a single point + if ( seg2Pt ) { + if (! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) ) return []; // but not in segment#1 + return [ inSeg2Pt1 ]; + } + + // they are collinear segments, which might overlap + var seg1min, seg1max, seg1minVal, seg1maxVal; + var seg2min, seg2max, seg2minVal, seg2maxVal; + if (seg1dx != 0) { // the segments are NOT on a vertical line + if ( inSeg1Pt1.x < inSeg1Pt2.x ) { + seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x; + seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x; + } else { + seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x; + seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x; + } + if ( inSeg2Pt1.x < inSeg2Pt2.x ) { + seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x; + seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x; + } else { + seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x; + seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x; + } + } else { // the segments are on a vertical line + if ( inSeg1Pt1.y < inSeg1Pt2.y ) { + seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y; + seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y; + } else { + seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y; + seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y; + } + if ( inSeg2Pt1.y < inSeg2Pt2.y ) { + seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y; + seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y; + } else { + seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y; + seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y; + } + } + if ( seg1minVal <= seg2minVal ) { + if ( seg1maxVal < seg2minVal ) return []; + if ( seg1maxVal == seg2minVal ) { + if ( inExcludeAdjacentSegs ) return []; + return [ seg2min ]; + } + if ( seg1maxVal <= seg2maxVal ) return [ seg2min, seg1max ]; + return [ seg2min, seg2max ]; + } else { + if ( seg1minVal > seg2maxVal ) return []; + if ( seg1minVal == seg2maxVal ) { + if ( inExcludeAdjacentSegs ) return []; + return [ seg1min ]; + } + if ( seg1maxVal <= seg2maxVal ) return [ seg1min, seg1max ]; + return [ seg1min, seg2max ]; + } + } + } + + function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) { + // The order of legs is important + + var EPSILON = 0.0000000001; + + // translation of all points, so that Vertex is at (0,0) + var legFromPtX = inLegFromPt.x - inVertex.x, legFromPtY = inLegFromPt.y - inVertex.y; + var legToPtX = inLegToPt.x - inVertex.x, legToPtY = inLegToPt.y - inVertex.y; + var otherPtX = inOtherPt.x - inVertex.x, otherPtY = inOtherPt.y - inVertex.y; + + // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg. + var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX; + var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX; + + if ( Math.abs(from2toAngle) > EPSILON ) { // angle != 180 deg. + + var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX; + // console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle ); + + if ( from2toAngle > 0 ) { // main angle < 180 deg. + return ( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) ); + } else { // main angle > 180 deg. + return ( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) ); + } + } else { // angle == 180 deg. + // console.log( "from2to: 180 deg., from2other: " + from2otherAngle ); + return ( from2otherAngle > 0 ); + } + } + + + function removeHoles( contour, holes ) { + + var shape = contour.concat(); // work on this shape + var hole; + + function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) { + // Check if hole point lies within angle around shape point + var lastShapeIdx = shape.length - 1; + + var prevShapeIdx = inShapeIdx - 1; + if ( prevShapeIdx < 0 ) prevShapeIdx = lastShapeIdx; + + var nextShapeIdx = inShapeIdx + 1; + if ( nextShapeIdx > lastShapeIdx ) nextShapeIdx = 0; + + var insideAngle = isPointInsideAngle( shape[inShapeIdx], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[inHoleIdx] ); + if (! insideAngle ) { + // console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y ); + return false; + } + + // Check if shape point lies within angle around hole point + var lastHoleIdx = hole.length - 1; + + var prevHoleIdx = inHoleIdx - 1; + if ( prevHoleIdx < 0 ) prevHoleIdx = lastHoleIdx; + + var nextHoleIdx = inHoleIdx + 1; + if ( nextHoleIdx > lastHoleIdx ) nextHoleIdx = 0; + + insideAngle = isPointInsideAngle( hole[inHoleIdx], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[inShapeIdx] ); + if (! insideAngle ) { + // console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y ); + return false; + } + + return true; + } + + function intersectsShapeEdge( inShapePt, inHolePt ) { + // checks for intersections with shape edges + var sIdx, nextIdx, intersection; + for ( sIdx = 0; sIdx < shape.length; sIdx++ ) { + nextIdx = sIdx+1; nextIdx %= shape.length; + intersection = intersect_segments_2D( inShapePt, inHolePt, shape[sIdx], shape[nextIdx], true ); + if ( intersection.length > 0 ) return true; + } + + return false; + } + + var indepHoles = []; + + function intersectsHoleEdge( inShapePt, inHolePt ) { + // checks for intersections with hole edges + var ihIdx, chkHole, + hIdx, nextIdx, intersection; + for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx++ ) { + chkHole = holes[indepHoles[ihIdx]]; + for ( hIdx = 0; hIdx < chkHole.length; hIdx++ ) { + nextIdx = hIdx+1; nextIdx %= chkHole.length; + intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[hIdx], chkHole[nextIdx], true ); + if ( intersection.length > 0 ) return true; + } + } + return false; + } + + var holeIndex, shapeIndex, + shapePt, holePt, + holeIdx, cutKey, failedCuts = [], + tmpShape1, tmpShape2, + tmpHole1, tmpHole2; + + for ( var h = 0, hl = holes.length; h < hl; h ++ ) { + + indepHoles.push( h ); + + } + + var counter = indepHoles.length * 2; + while ( indepHoles.length > 0 ) { + counter --; + if ( counter < 0 ) { + console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" ); + break; + } + + // search for shape-vertex and hole-vertex, + // which can be connected without intersections + for ( shapeIndex = 0; shapeIndex < shape.length; shapeIndex++ ) { + + shapePt = shape[ shapeIndex ]; + holeIndex = -1; + + // search for hole which can be reached without intersections + for ( var h = 0; h < indepHoles.length; h ++ ) { + holeIdx = indepHoles[h]; + + // prevent multiple checks + cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx; + if ( failedCuts[cutKey] !== undefined ) continue; + + hole = holes[holeIdx]; + for ( var h2 = 0; h2 < hole.length; h2 ++ ) { + holePt = hole[ h2 ]; + if (! isCutLineInsideAngles( shapeIndex, h2 ) ) continue; + if ( intersectsShapeEdge( shapePt, holePt ) ) continue; + if ( intersectsHoleEdge( shapePt, holePt ) ) continue; + + holeIndex = h2; + indepHoles.splice(h,1); + + tmpShape1 = shape.slice( 0, shapeIndex+1 ); + tmpShape2 = shape.slice( shapeIndex ); + tmpHole1 = hole.slice( holeIndex ); + tmpHole2 = hole.slice( 0, holeIndex+1 ); + + shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); + + // Debug only, to show the selected cuts + // glob_CutLines.push( [ shapePt, holePt ] ); + + break; + } + if ( holeIndex >= 0 ) break; // hole-vertex found + + failedCuts[cutKey] = true; // remember failure + } + if ( holeIndex >= 0 ) break; // hole-vertex found + } + } + + return shape; /* shape with no holes */ + } + + + var i, il, f, face, + key, index, + allPointsMap = {}; + + // 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. + + var allpoints = contour.concat(); + + for ( var h = 0, hl = holes.length; h < hl; h ++ ) { + + Array.prototype.push.apply( allpoints, holes[h] ); + + } + + //console.log( "allpoints",allpoints, allpoints.length ); + + // prepare all points map + + for ( i = 0, il = allpoints.length; i < il; i ++ ) { + + key = allpoints[ i ].x + ":" + allpoints[ i ].y; + + if ( allPointsMap[ key ] !== undefined ) { + + console.log( "Duplicate point", key ); + + } + + allPointsMap[ key ] = i; + + } + + // remove holes by cutting paths to holes and adding them to the shape + var shapeWithoutHoles = removeHoles( contour, holes ); + + var triangles = THREE.FontUtils.Triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape + //console.log( "triangles",triangles, triangles.length ); + + // check all face vertices against all points map + + for ( i = 0, il = triangles.length; i < il; i ++ ) { + + face = triangles[ i ]; + + for ( f = 0; f < 3; f ++ ) { + + key = face[ f ].x + ":" + face[ f ].y; + + index = allPointsMap[ key ]; + + if ( index !== undefined ) { + + face[ f ] = index; + + } + + } + + } + + return triangles.concat(); + + }, + + isClockWise: function ( pts ) { + + return THREE.FontUtils.Triangulate.area( pts ) < 0; + + }, + + // Bezier Curves formulas obtained from + // http://en.wikipedia.org/wiki/B%C3%A9zier_curve + + // Quad Bezier Functions + + b2p0: function ( t, p ) { + + var k = 1 - t; + return k * k * p; + + }, + + b2p1: function ( t, p ) { + + return 2 * ( 1 - t ) * t * p; + + }, + + b2p2: function ( t, p ) { + + return t * t * p; + + }, + + b2: function ( t, p0, p1, p2 ) { + + return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 ); + + }, + + // Cubic Bezier Functions + + b3p0: function ( t, p ) { + + var k = 1 - t; + return k * k * k * p; + + }, + + b3p1: function ( t, p ) { + + var k = 1 - t; + return 3 * k * k * t * p; + + }, + + b3p2: function ( t, p ) { + + var k = 1 - t; + return 3 * k * t * t * p; + + }, + + b3p3: function ( t, p ) { + + return t * t * t * p; + + }, + + b3: function ( t, p0, p1, p2, p3 ) { + + return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 ); + + } + +}; + + +/************************************************************** + * Line + **************************************************************/ + +THREE.LineCurve = function ( v1, v2 ) { + + this.v1 = v1; + this.v2 = v2; + +}; + +THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype ); + +THREE.LineCurve.prototype.getPoint = function ( t ) { + + var point = this.v2.clone().sub(this.v1); + point.multiplyScalar( t ).add( this.v1 ); + + return point; + +}; + +// Line curve is linear, so we can overwrite default getPointAt + +THREE.LineCurve.prototype.getPointAt = function ( u ) { + + return this.getPoint( u ); + +}; + +THREE.LineCurve.prototype.getTangent = function( t ) { + + var tangent = this.v2.clone().sub(this.v1); + + return tangent.normalize(); + +}; +/************************************************************** + * Quadratic Bezier curve + **************************************************************/ + + +THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + +}; + +THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype ); + + +THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) { + + var tx, ty; + + tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); + ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); + + return new THREE.Vector2( tx, ty ); + +}; + + +THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) { + + var tx, ty; + + tx = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x ); + ty = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y ); + + // returns unit vector + + var tangent = new THREE.Vector2( tx, ty ); + tangent.normalize(); + + return tangent; + +}; +/************************************************************** + * Cubic Bezier curve + **************************************************************/ + +THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + +}; + +THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype ); + +THREE.CubicBezierCurve.prototype.getPoint = function ( t ) { + + var tx, ty; + + tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); + + return new THREE.Vector2( tx, ty ); + +}; + +THREE.CubicBezierCurve.prototype.getTangent = function( t ) { + + var tx, ty; + + tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); + + var tangent = new THREE.Vector2( tx, ty ); + tangent.normalize(); + + return tangent; + +}; +/************************************************************** + * Spline curve + **************************************************************/ + +THREE.SplineCurve = function ( points /* array of Vector2 */ ) { + + this.points = (points == undefined) ? [] : points; + +}; + +THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype ); + +THREE.SplineCurve.prototype.getPoint = function ( t ) { + + var v = new THREE.Vector2(); + var c = []; + var points = this.points, point, intPoint, weight; + point = ( points.length - 1 ) * t; + + intPoint = Math.floor( point ); + weight = point - intPoint; + + c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > points.length - 2 ? points.length -1 : intPoint + 1; + c[ 3 ] = intPoint > points.length - 3 ? points.length -1 : intPoint + 2; + + v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); + v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); + + return v; + +}; +/************************************************************** + * Ellipse curve + **************************************************************/ + +THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { + + this.aX = aX; + this.aY = aY; + + this.xRadius = xRadius; + this.yRadius = yRadius; + + this.aStartAngle = aStartAngle; + this.aEndAngle = aEndAngle; + + this.aClockwise = aClockwise; + +}; + +THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype ); + +THREE.EllipseCurve.prototype.getPoint = function ( t ) { + + var angle; + var deltaAngle = this.aEndAngle - this.aStartAngle; + + if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2; + if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2; + + if ( this.aClockwise === true ) { + + angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle ); + + } else { + + angle = this.aStartAngle + t * deltaAngle; + + } + + var tx = this.aX + this.xRadius * Math.cos( angle ); + var ty = this.aY + this.yRadius * Math.sin( angle ); + + return new THREE.Vector2( tx, ty ); + +}; + +/************************************************************** + * Arc curve + **************************************************************/ + +THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + + THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); +}; + +THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype ); +/************************************************************** + * Line3D + **************************************************************/ + +THREE.LineCurve3 = THREE.Curve.create( + + function ( v1, v2 ) { + + this.v1 = v1; + this.v2 = v2; + + }, + + function ( t ) { + + var r = new THREE.Vector3(); + + + r.subVectors( this.v2, this.v1 ); // diff + r.multiplyScalar( t ); + r.add( this.v1 ); + + return r; + + } + +); + +/************************************************************** + * Quadratic Bezier 3D curve + **************************************************************/ + +THREE.QuadraticBezierCurve3 = THREE.Curve.create( + + function ( v0, v1, v2 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + + }, + + function ( t ) { + + var tx, ty, tz; + + tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); + ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); + tz = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z ); + + return new THREE.Vector3( tx, ty, tz ); + + } + +); +/************************************************************** + * Cubic Bezier 3D curve + **************************************************************/ + +THREE.CubicBezierCurve3 = THREE.Curve.create( + + function ( v0, v1, v2, v3 ) { + + this.v0 = v0; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + + }, + + function ( t ) { + + var tx, ty, tz; + + tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); + ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); + tz = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z ); + + return new THREE.Vector3( tx, ty, tz ); + + } + +); +/************************************************************** + * Spline 3D curve + **************************************************************/ + + +THREE.SplineCurve3 = THREE.Curve.create( + + function ( points /* array of Vector3 */) { + + this.points = (points == undefined) ? [] : points; + + }, + + function ( t ) { + + var v = new THREE.Vector3(); + var c = []; + var points = this.points, point, intPoint, weight; + point = ( points.length - 1 ) * t; + + intPoint = Math.floor( point ); + weight = point - intPoint; + + c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; + c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; + + var pt0 = points[ c[0] ], + pt1 = points[ c[1] ], + pt2 = points[ c[2] ], + pt3 = points[ c[3] ]; + + v.x = THREE.Curve.Utils.interpolate(pt0.x, pt1.x, pt2.x, pt3.x, weight); + v.y = THREE.Curve.Utils.interpolate(pt0.y, pt1.y, pt2.y, pt3.y, weight); + v.z = THREE.Curve.Utils.interpolate(pt0.z, pt1.z, pt2.z, pt3.z, weight); + + return v; + + } + +); + + +// THREE.SplineCurve3.prototype.getTangent = function(t) { +// var v = new THREE.Vector3(); +// var c = []; +// var points = this.points, point, intPoint, weight; +// point = ( points.length - 1 ) * t; + +// intPoint = Math.floor( point ); +// weight = point - intPoint; + +// c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; +// c[ 1 ] = intPoint; +// c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; +// c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; + +// var pt0 = points[ c[0] ], +// pt1 = points[ c[1] ], +// pt2 = points[ c[2] ], +// pt3 = points[ c[3] ]; + +// // t = weight; +// v.x = THREE.Curve.Utils.tangentSpline( t, pt0.x, pt1.x, pt2.x, pt3.x ); +// v.y = THREE.Curve.Utils.tangentSpline( t, pt0.y, pt1.y, pt2.y, pt3.y ); +// v.z = THREE.Curve.Utils.tangentSpline( t, pt0.z, pt1.z, pt2.z, pt3.z ); + +// return v; + +// } +/************************************************************** + * Closed Spline 3D curve + **************************************************************/ + + +THREE.ClosedSplineCurve3 = THREE.Curve.create( + + function ( points /* array of Vector3 */) { + + this.points = (points == undefined) ? [] : points; + + }, + + function ( t ) { + + var v = new THREE.Vector3(); + var c = []; + var points = this.points, point, intPoint, weight; + point = ( points.length - 0 ) * t; + // This needs to be from 0-length +1 + + intPoint = Math.floor( point ); + weight = point - intPoint; + + intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; + c[ 0 ] = ( intPoint - 1 ) % points.length; + c[ 1 ] = ( intPoint ) % points.length; + c[ 2 ] = ( intPoint + 1 ) % points.length; + c[ 3 ] = ( intPoint + 2 ) % points.length; + + v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); + v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); + v.z = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].z, points[ c[ 1 ] ].z, points[ c[ 2 ] ].z, points[ c[ 3 ] ].z, weight ); + + return v; + + } + +); +/** + * @author mikael emtinger / http://gomo.se/ + */ + +THREE.AnimationHandler = (function() { + + var playing = []; + var library = {}; + var that = {}; + + + //--- update --- + + that.update = function( deltaTimeMS ) { + + for( var i = 0; i < playing.length; i ++ ) + playing[ i ].update( deltaTimeMS ); + + }; + + + //--- add --- + + that.addToUpdate = function( animation ) { + + if ( playing.indexOf( animation ) === -1 ) + playing.push( animation ); + + }; + + + //--- remove --- + + that.removeFromUpdate = function( animation ) { + + var index = playing.indexOf( animation ); + + if( index !== -1 ) + playing.splice( index, 1 ); + + }; + + + //--- add --- + + that.add = function( data ) { + + if ( library[ data.name ] !== undefined ) + THREE.onwarning( "THREE.AnimationHandler.add: Warning! " + data.name + " already exists in library. Overwriting." ); + + library[ data.name ] = data; + initData( data ); + + }; + + + //--- get --- + + that.get = function( name ) { + + if ( typeof name === "string" ) { + + if ( library[ name ] ) { + + return library[ name ]; + + } else { + + THREE.onwarning( "THREE.AnimationHandler.get: Couldn't find animation " + name ); + return null; + + } + + } else { + + // todo: add simple tween library + + } + + }; + + //--- parse --- + + that.parse = function( root ) { + + // setup hierarchy + + var hierarchy = []; + + if ( root instanceof THREE.SkinnedMesh ) { + + for( var b = 0; b < root.bones.length; b++ ) { + + hierarchy.push( root.bones[ b ] ); + + } + + } else { + + parseRecurseHierarchy( root, hierarchy ); + + } + + return hierarchy; + + }; + + var parseRecurseHierarchy = function( root, hierarchy ) { + + hierarchy.push( root ); + + for( var c = 0; c < root.children.length; c++ ) + parseRecurseHierarchy( root.children[ c ], hierarchy ); + + } + + + //--- init data --- + + var initData = function( data ) { + + if( data.initialized === true ) + return; + + + // loop through all keys + + for( var h = 0; h < data.hierarchy.length; h ++ ) { + + for( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + + // remove minus times + + if( data.hierarchy[ h ].keys[ k ].time < 0 ) + data.hierarchy[ h ].keys[ k ].time = 0; + + + // create quaternions + + if( data.hierarchy[ h ].keys[ k ].rot !== undefined && + !( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) { + + var quat = data.hierarchy[ h ].keys[ k ].rot; + data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion( quat[0], quat[1], quat[2], quat[3] ); + + } + + } + + + // prepare morph target keys + + if( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) { + + // get all used + + var usedMorphTargets = {}; + + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + + for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { + + var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ]; + usedMorphTargets[ morphTargetName ] = -1; + + } + + } + + data.hierarchy[ h ].usedMorphTargets = usedMorphTargets; + + + // set all used on all frames + + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + + var influences = {}; + + for ( var morphTargetName in usedMorphTargets ) { + + for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { + + if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) { + + influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ]; + break; + + } + + } + + if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) { + + influences[ morphTargetName ] = 0; + + } + + } + + data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences; + + } + + } + + + // remove all keys that are on the same time + + for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) { + + if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) { + + data.hierarchy[ h ].keys.splice( k, 1 ); + k --; + + } + + } + + + // set index + + for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { + + data.hierarchy[ h ].keys[ k ].index = k; + + } + + } + + // done + + data.initialized = true; + + }; + + + // interpolation types + + that.LINEAR = 0; + that.CATMULLROM = 1; + that.CATMULLROM_FORWARD = 2; + + return that; + +}()); + +/** + * @author mikael emtinger / http://gomo.se/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.Animation = function ( root, name ) { + + this.root = root; + this.data = THREE.AnimationHandler.get( name ); + this.hierarchy = THREE.AnimationHandler.parse( root ); + + this.currentTime = 0; + this.timeScale = 1; + + this.isPlaying = false; + this.isPaused = true; + this.loop = true; + + this.interpolationType = THREE.AnimationHandler.LINEAR; + +}; + +THREE.Animation.prototype.play = function ( startTime ) { + + this.currentTime = startTime !== undefined ? startTime : 0; + + if ( this.isPlaying === false ) { + + this.isPlaying = true; + + this.reset(); + this.update( 0 ); + + } + + this.isPaused = false; + + THREE.AnimationHandler.addToUpdate( this ); + +}; + + +THREE.Animation.prototype.pause = function() { + + if ( this.isPaused === true ) { + + THREE.AnimationHandler.addToUpdate( this ); + + } else { + + THREE.AnimationHandler.removeFromUpdate( this ); + + } + + this.isPaused = !this.isPaused; + +}; + + +THREE.Animation.prototype.stop = function() { + + this.isPlaying = false; + this.isPaused = false; + THREE.AnimationHandler.removeFromUpdate( this ); + +}; + +THREE.Animation.prototype.reset = function () { + + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + + var object = this.hierarchy[ h ]; + + object.matrixAutoUpdate = true; + + if ( object.animationCache === undefined ) { + + object.animationCache = {}; + object.animationCache.prevKey = { pos: 0, rot: 0, scl: 0 }; + object.animationCache.nextKey = { pos: 0, rot: 0, scl: 0 }; + object.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; + + } + + var prevKey = object.animationCache.prevKey; + var nextKey = object.animationCache.nextKey; + + prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ]; + prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ]; + prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ]; + + nextKey.pos = this.getNextKeyWith( "pos", h, 1 ); + nextKey.rot = this.getNextKeyWith( "rot", h, 1 ); + nextKey.scl = this.getNextKeyWith( "scl", h, 1 ); + + } + +}; + + +THREE.Animation.prototype.update = (function(){ + + var points = []; + var target = new THREE.Vector3(); + + // Catmull-Rom spline + + var interpolateCatmullRom = function ( points, scale ) { + + var c = [], v3 = [], + point, intPoint, weight, w2, w3, + pa, pb, pc, pd; + + point = ( points.length - 1 ) * scale; + intPoint = Math.floor( point ); + weight = point - intPoint; + + c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; + c[ 1 ] = intPoint; + c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1; + c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2; + + pa = points[ c[ 0 ] ]; + pb = points[ c[ 1 ] ]; + pc = points[ c[ 2 ] ]; + pd = points[ c[ 3 ] ]; + + w2 = weight * weight; + w3 = weight * w2; + + v3[ 0 ] = interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 ); + v3[ 1 ] = interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 ); + v3[ 2 ] = interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 ); + + return v3; + + }; + + var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) { + + var v0 = ( p2 - p0 ) * 0.5, + v1 = ( p3 - p1 ) * 0.5; + + return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; + + }; + + return function ( delta ) { + if ( this.isPlaying === false ) return; + + this.currentTime += delta * this.timeScale; + + // + + var vector; + var types = [ "pos", "rot", "scl" ]; + + var duration = this.data.length; + + if ( this.loop === true && this.currentTime > duration ) { + + this.currentTime %= duration; + this.reset(); + + } else if ( this.loop === false && this.currentTime > duration ) { + + this.stop(); + return; + + } + + this.currentTime = Math.min( this.currentTime, duration ); + + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + + var object = this.hierarchy[ h ]; + var animationCache = object.animationCache; + + // loop through pos/rot/scl + + for ( var t = 0; t < 3; t ++ ) { + + // get keys + + var type = types[ t ]; + var prevKey = animationCache.prevKey[ type ]; + var nextKey = animationCache.nextKey[ type ]; + + if ( nextKey.time <= this.currentTime ) { + + prevKey = this.data.hierarchy[ h ].keys[ 0 ]; + nextKey = this.getNextKeyWith( type, h, 1 ); + + while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { + + prevKey = nextKey; + nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); + + } + + animationCache.prevKey[ type ] = prevKey; + animationCache.nextKey[ type ] = nextKey; + + } + + object.matrixAutoUpdate = true; + object.matrixWorldNeedsUpdate = true; + + var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time ); + + var prevXYZ = prevKey[ type ]; + var nextXYZ = nextKey[ type ]; + + if ( scale < 0 ) scale = 0; + if ( scale > 1 ) scale = 1; + + // interpolate + + if ( type === "pos" ) { + + vector = object.position; + + if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) { + + vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; + vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; + vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; + + } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + + points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ]; + points[ 1 ] = prevXYZ; + points[ 2 ] = nextXYZ; + points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ]; + + scale = scale * 0.33 + 0.33; + + var currentPoint = interpolateCatmullRom( points, scale ); + + vector.x = currentPoint[ 0 ]; + vector.y = currentPoint[ 1 ]; + vector.z = currentPoint[ 2 ]; + + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + + var forwardPoint = interpolateCatmullRom( points, scale * 1.01 ); + + target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] ); + target.sub( vector ); + target.y = 0; + target.normalize(); + + var angle = Math.atan2( target.x, target.z ); + object.rotation.set( 0, angle, 0 ); + + } + + } + + } else if ( type === "rot" ) { + + THREE.Quaternion.slerp( prevXYZ, nextXYZ, object.quaternion, scale ); + + } else if ( type === "scl" ) { + + vector = object.scale; + + vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; + vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; + vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; + + } + + } + + } + + }; + +})(); + + + + + +// Get next key with + +THREE.Animation.prototype.getNextKeyWith = function ( type, h, key ) { + + var keys = this.data.hierarchy[ h ].keys; + + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + + key = key < keys.length - 1 ? key : keys.length - 1; + + } else { + + key = key % keys.length; + + } + + for ( ; key < keys.length; key++ ) { + + if ( keys[ key ][ type ] !== undefined ) { + + return keys[ key ]; + + } + + } + + return this.data.hierarchy[ h ].keys[ 0 ]; + +}; + +// Get previous key with + +THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) { + + var keys = this.data.hierarchy[ h ].keys; + + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + + key = key > 0 ? key : 0; + + } else { + + key = key >= 0 ? key : key + keys.length; + + } + + + for ( ; key >= 0; key -- ) { + + if ( keys[ key ][ type ] !== undefined ) { + + return keys[ key ]; + + } + + } + + return this.data.hierarchy[ h ].keys[ keys.length - 1 ]; + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + * @author khang duong + * @author erik kitson + */ + +THREE.KeyFrameAnimation = function ( root, data ) { + + this.root = root; + this.data = THREE.AnimationHandler.get( data ); + this.hierarchy = THREE.AnimationHandler.parse( root ); + this.currentTime = 0; + this.timeScale = 0.001; + this.isPlaying = false; + this.isPaused = true; + this.loop = true; + + // initialize to first keyframes + + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + + var keys = this.data.hierarchy[h].keys, + sids = this.data.hierarchy[h].sids, + obj = this.hierarchy[h]; + + if ( keys.length && sids ) { + + for ( var s = 0; s < sids.length; s++ ) { + + var sid = sids[ s ], + next = this.getNextKeyWith( sid, h, 0 ); + + if ( next ) { + + next.apply( sid ); + + } + + } + + obj.matrixAutoUpdate = false; + this.data.hierarchy[h].node.updateMatrix(); + obj.matrixWorldNeedsUpdate = true; + + } + + } + +}; + +// Play + +THREE.KeyFrameAnimation.prototype.play = function ( startTime ) { + + this.currentTime = startTime !== undefined ? startTime : 0; + + if ( this.isPlaying === false ) { + + this.isPlaying = true; + + // reset key cache + + var h, hl = this.hierarchy.length, + object, + node; + + for ( h = 0; h < hl; h++ ) { + + object = this.hierarchy[ h ]; + node = this.data.hierarchy[ h ]; + + if ( node.animationCache === undefined ) { + + node.animationCache = {}; + node.animationCache.prevKey = null; + node.animationCache.nextKey = null; + node.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; + + } + + var keys = this.data.hierarchy[h].keys; + + if (keys.length) { + + node.animationCache.prevKey = keys[ 0 ]; + node.animationCache.nextKey = keys[ 1 ]; + + this.startTime = Math.min( keys[0].time, this.startTime ); + this.endTime = Math.max( keys[keys.length - 1].time, this.endTime ); + + } + + } + + this.update( 0 ); + + } + + this.isPaused = false; + + THREE.AnimationHandler.addToUpdate( this ); + +}; + + + +// Pause + +THREE.KeyFrameAnimation.prototype.pause = function() { + + if( this.isPaused ) { + + THREE.AnimationHandler.addToUpdate( this ); + + } else { + + THREE.AnimationHandler.removeFromUpdate( this ); + + } + + this.isPaused = !this.isPaused; + +}; + + +// Stop + +THREE.KeyFrameAnimation.prototype.stop = function() { + + this.isPlaying = false; + this.isPaused = false; + + THREE.AnimationHandler.removeFromUpdate( this ); + + // reset JIT matrix and remove cache + + for ( var h = 0; h < this.data.hierarchy.length; h++ ) { + + var obj = this.hierarchy[ h ]; + var node = this.data.hierarchy[ h ]; + + if ( node.animationCache !== undefined ) { + + var original = node.animationCache.originalMatrix; + + if( obj instanceof THREE.Bone ) { + + original.copy( obj.skinMatrix ); + obj.skinMatrix = original; + + } else { + + original.copy( obj.matrix ); + obj.matrix = original; + + } + + delete node.animationCache; + + } + + } + +}; + + +// Update + +THREE.KeyFrameAnimation.prototype.update = function ( delta ) { + + if ( this.isPlaying === false ) return; + + this.currentTime += delta * this.timeScale; + + // + + var duration = this.data.length; + + if ( this.loop === true && this.currentTime > duration ) { + + this.currentTime %= duration; + + } + + this.currentTime = Math.min( this.currentTime, duration ); + + for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) { + + var object = this.hierarchy[ h ]; + var node = this.data.hierarchy[ h ]; + + var keys = node.keys, + animationCache = node.animationCache; + + + if ( keys.length ) { + + var prevKey = animationCache.prevKey; + var nextKey = animationCache.nextKey; + + if ( nextKey.time <= this.currentTime ) { + + while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { + + prevKey = nextKey; + nextKey = keys[ prevKey.index + 1 ]; + + } + + animationCache.prevKey = prevKey; + animationCache.nextKey = nextKey; + + } + + if ( nextKey.time >= this.currentTime ) { + + prevKey.interpolate( nextKey, this.currentTime ); + + } else { + + prevKey.interpolate( nextKey, nextKey.time ); + + } + + this.data.hierarchy[ h ].node.updateMatrix(); + object.matrixWorldNeedsUpdate = true; + + } + + } + +}; + +// Get next key with + +THREE.KeyFrameAnimation.prototype.getNextKeyWith = function( sid, h, key ) { + + var keys = this.data.hierarchy[ h ].keys; + key = key % keys.length; + + for ( ; key < keys.length; key++ ) { + + if ( keys[ key ].hasTarget( sid ) ) { + + return keys[ key ]; + + } + + } + + return keys[ 0 ]; + +}; + +// Get previous key with + +THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) { + + var keys = this.data.hierarchy[ h ].keys; + key = key >= 0 ? key : key + keys.length; + + for ( ; key >= 0; key-- ) { + + if ( keys[ key ].hasTarget( sid ) ) { + + return keys[ key ]; + + } + + } + + return keys[ keys.length - 1 ]; + +}; + +/** + * @author mrdoob / http://mrdoob.com + */ + +THREE.MorphAnimation = function ( mesh ) { + + this.mesh = mesh; + this.frames = mesh.morphTargetInfluences.length; + this.currentTime = 0; + this.duration = 1000; + this.loop = true; + + this.isPlaying = false; + +}; + +THREE.MorphAnimation.prototype = { + + play: function () { + + this.isPlaying = true; + + }, + + pause: function () { + + this.isPlaying = false; + }, + + update: ( function () { + + var lastFrame = 0; + var currentFrame = 0; + + return function ( delta ) { + + if ( this.isPlaying === false ) return; + + this.currentTime += delta; + + if ( this.loop === true && this.currentTime > this.duration ) { + + this.currentTime %= this.duration; + + } + + this.currentTime = Math.min( this.currentTime, this.duration ); + + var interpolation = this.duration / this.frames; + var frame = Math.floor( this.currentTime / interpolation ); + + if ( frame != currentFrame ) { + + this.mesh.morphTargetInfluences[ lastFrame ] = 0; + this.mesh.morphTargetInfluences[ currentFrame ] = 1; + this.mesh.morphTargetInfluences[ frame ] = 0; + + lastFrame = currentFrame; + currentFrame = frame; + + } + + this.mesh.morphTargetInfluences[ frame ] = ( this.currentTime % interpolation ) / interpolation; + this.mesh.morphTargetInfluences[ lastFrame ] = 1 - this.mesh.morphTargetInfluences[ frame ]; + + } + + } )() + +}; + +/** + * Camera for rendering cube maps + * - renders scene into axis-aligned cube + * + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.CubeCamera = function ( near, far, cubeResolution ) { + + THREE.Object3D.call( this ); + this.className = "CubeCamera"; + + var fov = 90, aspect = 1; + + var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPX.up.set( 0, -1, 0 ); + cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) ); + this.add( cameraPX ); + + var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNX.up.set( 0, -1, 0 ); + cameraNX.lookAt( new THREE.Vector3( -1, 0, 0 ) ); + this.add( cameraNX ); + + var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPY.up.set( 0, 0, 1 ); + cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) ); + this.add( cameraPY ); + + var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNY.up.set( 0, 0, -1 ); + cameraNY.lookAt( new THREE.Vector3( 0, -1, 0 ) ); + this.add( cameraNY ); + + var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraPZ.up.set( 0, -1, 0 ); + cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) ); + this.add( cameraPZ ); + + var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); + cameraNZ.up.set( 0, -1, 0 ); + cameraNZ.lookAt( new THREE.Vector3( 0, 0, -1 ) ); + this.add( cameraNZ ); + + this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } ); + + this.updateCubeMap = function ( renderer, scene ) { + + var renderTarget = this.renderTarget; + var generateMipmaps = renderTarget.generateMipmaps; + + renderTarget.generateMipmaps = false; + + renderTarget.activeCubeFace = 0; + renderer.render( scene, cameraPX, renderTarget ); + + renderTarget.activeCubeFace = 1; + renderer.render( scene, cameraNX, renderTarget ); + + renderTarget.activeCubeFace = 2; + renderer.render( scene, cameraPY, renderTarget ); + + renderTarget.activeCubeFace = 3; + renderer.render( scene, cameraNY, renderTarget ); + + renderTarget.activeCubeFace = 4; + renderer.render( scene, cameraPZ, renderTarget ); + + renderTarget.generateMipmaps = generateMipmaps; + + renderTarget.activeCubeFace = 5; + renderer.render( scene, cameraNZ, renderTarget ); + + }; + +}; + +THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); + +/** + * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog + * + * A general perpose camera, for setting FOV, Lens Focal Length, + * and switching between perspective and orthographic views easily. + * Use this only if you do not wish to manage + * both a Orthographic and Perspective Camera + * + */ + + +THREE.CombinedCamera = function ( width, height, fov, near, far, orthoNear, orthoFar ) { + + THREE.Camera.call( this ); + this.className = "CombinedCamera"; + + this.fov = fov; + + this.left = -width / 2; + this.right = width / 2 + this.top = height / 2; + this.bottom = -height / 2; + + // We could also handle the projectionMatrix internally, but just wanted to test nested camera objects + + this.cameraO = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, orthoNear, orthoFar ); + this.cameraP = new THREE.PerspectiveCamera( fov, width / height, near, far ); + + this.zoom = 1; + + this.toPerspective(); + + var aspect = width/height; + +}; + +THREE.CombinedCamera.prototype = Object.create( THREE.Camera.prototype ); + +THREE.CombinedCamera.prototype.toPerspective = function () { + + // Switches to the Perspective Camera + + this.near = this.cameraP.near; + this.far = this.cameraP.far; + + this.cameraP.fov = this.fov / this.zoom ; + + this.cameraP.updateProjectionMatrix(); + + this.projectionMatrix = this.cameraP.projectionMatrix; + + this.inPerspectiveMode = true; + this.inOrthographicMode = false; + +}; + +THREE.CombinedCamera.prototype.toOrthographic = function () { + + // Switches to the Orthographic camera estimating viewport from Perspective + + var fov = this.fov; + var aspect = this.cameraP.aspect; + var near = this.cameraP.near; + var far = this.cameraP.far; + + // The size that we set is the mid plane of the viewing frustum + + var hyperfocus = ( near + far ) / 2; + + var halfHeight = Math.tan( fov / 2 ) * hyperfocus; + var planeHeight = 2 * halfHeight; + var planeWidth = planeHeight * aspect; + var halfWidth = planeWidth / 2; + + halfHeight /= this.zoom; + halfWidth /= this.zoom; + + this.cameraO.left = -halfWidth; + this.cameraO.right = halfWidth; + this.cameraO.top = halfHeight; + this.cameraO.bottom = -halfHeight; + + // this.cameraO.left = -farHalfWidth; + // this.cameraO.right = farHalfWidth; + // this.cameraO.top = farHalfHeight; + // this.cameraO.bottom = -farHalfHeight; + + // this.cameraO.left = this.left / this.zoom; + // this.cameraO.right = this.right / this.zoom; + // this.cameraO.top = this.top / this.zoom; + // this.cameraO.bottom = this.bottom / this.zoom; + + this.cameraO.updateProjectionMatrix(); + + this.near = this.cameraO.near; + this.far = this.cameraO.far; + this.projectionMatrix = this.cameraO.projectionMatrix; + + this.inPerspectiveMode = false; + this.inOrthographicMode = true; + +}; + + +THREE.CombinedCamera.prototype.setSize = function( width, height ) { + + this.cameraP.aspect = width / height; + this.left = -width / 2; + this.right = width / 2 + this.top = height / 2; + this.bottom = -height / 2; + +}; + + +THREE.CombinedCamera.prototype.setFov = function( fov ) { + + this.fov = fov; + + if ( this.inPerspectiveMode ) { + + this.toPerspective(); + + } else { + + this.toOrthographic(); + + } + +}; + +// For mantaining similar API with PerspectiveCamera + +THREE.CombinedCamera.prototype.updateProjectionMatrix = function() { + + if ( this.inPerspectiveMode ) { + + this.toPerspective(); + + } else { + + this.toPerspective(); + this.toOrthographic(); + + } + +}; + +/* +* Uses Focal Length (in mm) to estimate and set FOV +* 35mm (fullframe) camera is used if frame size is not specified; +* Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html +*/ +THREE.CombinedCamera.prototype.setLens = function ( focalLength, frameHeight ) { + + if ( frameHeight === undefined ) frameHeight = 24; + + var fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); + + this.setFov( fov ); + + return fov; +}; + + +THREE.CombinedCamera.prototype.setZoom = function( zoom ) { + + this.zoom = zoom; + + if ( this.inPerspectiveMode ) { + + this.toPerspective(); + + } else { + + this.toOrthographic(); + + } + +}; + +THREE.CombinedCamera.prototype.toFrontView = function() { + + this.rotation.x = 0; + this.rotation.y = 0; + this.rotation.z = 0; + + // should we be modifing the matrix instead? + + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toBackView = function() { + + this.rotation.x = 0; + this.rotation.y = Math.PI; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toLeftView = function() { + + this.rotation.x = 0; + this.rotation.y = - Math.PI / 2; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toRightView = function() { + + this.rotation.x = 0; + this.rotation.y = Math.PI / 2; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toTopView = function() { + + this.rotation.x = - Math.PI / 2; + this.rotation.y = 0; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +THREE.CombinedCamera.prototype.toBottomView = function() { + + this.rotation.x = Math.PI / 2; + this.rotation.y = 0; + this.rotation.z = 0; + this.rotationAutoUpdate = false; + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as + */ + +THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { + + THREE.Geometry.call( this ); + this.className = "BoxGeometry"; + + var scope = this; + + this.width = width; + this.height = height; + this.depth = depth; + + this.widthSegments = widthSegments || 1; + this.heightSegments = heightSegments || 1; + this.depthSegments = depthSegments || 1; + + var width_half = this.width / 2; + var height_half = this.height / 2; + var depth_half = this.depth / 2; + + buildPlane( 'z', 'y', - 1, - 1, this.depth, this.height, width_half, 0 ); // px + buildPlane( 'z', 'y', 1, - 1, this.depth, this.height, - width_half, 1 ); // nx + buildPlane( 'x', 'z', 1, 1, this.width, this.depth, height_half, 2 ); // py + buildPlane( 'x', 'z', 1, - 1, this.width, this.depth, - height_half, 3 ); // ny + buildPlane( 'x', 'y', 1, - 1, this.width, this.height, depth_half, 4 ); // pz + buildPlane( 'x', 'y', - 1, - 1, this.width, this.height, - depth_half, 5 ); // nz + + function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) { + + var w, ix, iy, + gridX = scope.widthSegments, + gridY = scope.heightSegments, + width_half = width / 2, + height_half = height / 2, + offset = scope.vertices.length; + + if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) { + + w = 'z'; + + } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) { + + w = 'y'; + gridY = scope.depthSegments; + + } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) { + + w = 'x'; + gridX = scope.depthSegments; + + } + + var gridX1 = gridX + 1, + gridY1 = gridY + 1, + segment_width = width / gridX, + segment_height = height / gridY, + normal = new THREE.Vector3(); + + normal[ w ] = depth > 0 ? 1 : - 1; + + for ( iy = 0; iy < gridY1; iy ++ ) { + + for ( ix = 0; ix < gridX1; ix ++ ) { + + var vector = new THREE.Vector3(); + vector[ u ] = ( ix * segment_width - width_half ) * udir; + vector[ v ] = ( iy * segment_height - height_half ) * vdir; + vector[ w ] = depth; + + scope.vertices.push( vector ); + + } + + } + + for ( iy = 0; iy < gridY; iy++ ) { + + for ( ix = 0; ix < gridX; ix++ ) { + + var a = ix + gridX1 * iy; + var b = ix + gridX1 * ( iy + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = ( ix + 1 ) + gridX1 * iy; + + var uva = new THREE.Vector2( ix / gridX, 1 - iy / gridY ); + var uvb = new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY ); + var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iy + 1 ) / gridY ); + var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY ); + + var face = new THREE.Face3( a + offset, b + offset, d + offset ); + face.normal.copy( normal ); + face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); + face.materialIndex = materialIndex; + + scope.faces.push( face ); + scope.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); + + face = new THREE.Face3( b + offset, c + offset, d + offset ); + face.normal.copy( normal ); + face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); + face.materialIndex = materialIndex; + + scope.faces.push( face ); + scope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); + + } + + } + + } + + this.computeCentroids(); + this.mergeVertices(); + +}; + +THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author hughes + */ + +THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { + + THREE.Geometry.call( this ); + this.className = "CircleGeometry"; + + this.radius = radius = radius || 50; + this.segments = segments = segments !== undefined ? Math.max( 3, segments ) : 8; + + this.thetaStart = thetaStart = thetaStart !== undefined ? thetaStart : 0; + this.thetaLength = thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + + var i, uvs = [], + center = new THREE.Vector3(), centerUV = new THREE.Vector2( 0.5, 0.5 ); + + this.vertices.push(center); + uvs.push( centerUV ); + + for ( i = 0; i <= segments; i ++ ) { + + var vertex = new THREE.Vector3(); + var segment = thetaStart + i / segments * thetaLength; + + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); + + this.vertices.push( vertex ); + uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, ( vertex.y / radius + 1 ) / 2 ) ); + + } + + var n = new THREE.Vector3( 0, 0, 1 ); + + for ( i = 1; i <= segments; i ++ ) { + + var v1 = i; + var v2 = i + 1 ; + var v3 = 0; + + this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[ i ].clone(), uvs[ i + 1 ].clone(), centerUV.clone() ] ); + + } + + this.computeCentroids(); + this.computeFaceNormals(); + + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + +}; + +THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +// DEPRECATED + +THREE.CubeGeometry = THREE.BoxGeometry; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded ) { + + THREE.Geometry.call( this ); + this.className = "CylinderGeometry"; + + this.radiusTop = radiusTop = radiusTop !== undefined ? radiusTop : 20; + this.radiusBottom = radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; + this.height = height = height !== undefined ? height : 100; + + this.radialSegments = radialSegments = radialSegments || 8; + this.heightSegments = heightSegments = heightSegments || 1; + + this.openEnded = openEnded = openEnded !== undefined ? openEnded : false; + + var heightHalf = height / 2; + + var x, y, vertices = [], uvs = []; + + for ( y = 0; y <= heightSegments; y ++ ) { + + var verticesRow = []; + var uvsRow = []; + + var v = y / heightSegments; + var radius = v * ( radiusBottom - radiusTop ) + radiusTop; + + for ( x = 0; x <= radialSegments; x ++ ) { + + var u = x / radialSegments; + + var vertex = new THREE.Vector3(); + vertex.x = radius * Math.sin( u * Math.PI * 2 ); + vertex.y = - v * height + heightHalf; + vertex.z = radius * Math.cos( u * Math.PI * 2 ); + + this.vertices.push( vertex ); + + verticesRow.push( this.vertices.length - 1 ); + uvsRow.push( new THREE.Vector2( u, 1 - v ) ); + + } + + vertices.push( verticesRow ); + uvs.push( uvsRow ); + + } + + var tanTheta = ( radiusBottom - radiusTop ) / height; + var na, nb; + + for ( x = 0; x < radialSegments; x ++ ) { + + if ( radiusTop !== 0 ) { + + na = this.vertices[ vertices[ 0 ][ x ] ].clone(); + nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone(); + + } else { + + na = this.vertices[ vertices[ 1 ][ x ] ].clone(); + nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone(); + + } + + na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize(); + nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize(); + + for ( y = 0; y < heightSegments; y ++ ) { + + var v1 = vertices[ y ][ x ]; + var v2 = vertices[ y + 1 ][ x ]; + var v3 = vertices[ y + 1 ][ x + 1 ]; + var v4 = vertices[ y ][ x + 1 ]; + + var n1 = na.clone(); + var n2 = na.clone(); + var n3 = nb.clone(); + var n4 = nb.clone(); + + var uv1 = uvs[ y ][ x ].clone(); + var uv2 = uvs[ y + 1 ][ x ].clone(); + var uv3 = uvs[ y + 1 ][ x + 1 ].clone(); + var uv4 = uvs[ y ][ x + 1 ].clone(); + + this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); + + this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); + + } + + } + + // top cap + + if ( openEnded === false && radiusTop > 0 ) { + + this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) ); + + for ( x = 0; x < radialSegments; x ++ ) { + + var v1 = vertices[ 0 ][ x ]; + var v2 = vertices[ 0 ][ x + 1 ]; + var v3 = this.vertices.length - 1; + + var n1 = new THREE.Vector3( 0, 1, 0 ); + var n2 = new THREE.Vector3( 0, 1, 0 ); + var n3 = new THREE.Vector3( 0, 1, 0 ); + + var uv1 = uvs[ 0 ][ x ].clone(); + var uv2 = uvs[ 0 ][ x + 1 ].clone(); + var uv3 = new THREE.Vector2( uv2.x, 0 ); + + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + + } + + } + + // bottom cap + + if ( openEnded === false && radiusBottom > 0 ) { + + this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) ); + + for ( x = 0; x < radialSegments; x ++ ) { + + var v1 = vertices[ y ][ x + 1 ]; + var v2 = vertices[ y ][ x ]; + var v3 = this.vertices.length - 1; + + var n1 = new THREE.Vector3( 0, - 1, 0 ); + var n2 = new THREE.Vector3( 0, - 1, 0 ); + var n3 = new THREE.Vector3( 0, - 1, 0 ); + + var uv1 = uvs[ y ][ x + 1 ].clone(); + var uv2 = uvs[ y ][ x ].clone(); + var uv3 = new THREE.Vector2( uv2.x, 1 ); + + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + + } + + } + + this.computeCentroids(); + this.computeFaceNormals(); + +} + +THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * + * Creates extruded geometry from a path shape. + * + * parameters = { + * + * curveSegments: , // number of points on the curves + * steps: , // number of points for z-side extrusions / used for subdividing segements of extrude spline too + * amount: , // Depth to extrude the shape + * + * bevelEnabled: , // turn on bevel + * bevelThickness: , // how deep into the original shape bevel goes + * bevelSize: , // how far from shape outline is bevel + * bevelSegments: , // number of bevel layers + * + * extrudePath: // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined) + * frames: // containing arrays of tangents, normals, binormals + * + * material: // material index for front and back faces + * extrudeMaterial: // material index for extrusion and beveled faces + * uvGenerator: // object that provides UV generator functions + * + * } + **/ + +THREE.ExtrudeGeometry = function ( shapes, options ) { + + if ( typeof( shapes ) === "undefined" ) { + shapes = []; + return; + } + + THREE.Geometry.call( this ); + this.className = "ExtrudeGeometry"; + + shapes = shapes instanceof Array ? shapes : [ shapes ]; + + this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); + + this.addShapeList( shapes, options ); + + this.computeCentroids(); + this.computeFaceNormals(); + + // can't really use automatic vertex normals + // as then front and back sides get smoothed too + // should do separate smoothing just for sides + + //this.computeVertexNormals(); + + //console.log( "took", ( Date.now() - startTime ) ); + +}; + +THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +THREE.ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) { + var sl = shapes.length; + + for ( var s = 0; s < sl; s ++ ) { + var shape = shapes[ s ]; + this.addShape( shape, options ); + } +}; + +THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { + + var amount = options.amount !== undefined ? options.amount : 100; + + var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10 + var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8 + var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; + + var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false + + var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + + var steps = options.steps !== undefined ? options.steps : 1; + + var extrudePath = options.extrudePath; + var extrudePts, extrudeByPath = false; + + var material = options.material; + var extrudeMaterial = options.extrudeMaterial; + + // Use default WorldUVGenerator if no UV generators are specified. + var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator; + + var shapebb = this.shapebb; + //shapebb = shape.getBoundingBox(); + + + + var splineTube, binormal, normal, position2; + if ( extrudePath ) { + + extrudePts = extrudePath.getSpacedPoints( steps ); + + extrudeByPath = true; + bevelEnabled = false; // bevels not supported for path extrusion + + // SETUP TNB variables + + // Reuse TNB from TubeGeomtry for now. + // TODO1 - have a .isClosed in spline? + + splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false); + + // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); + + binormal = new THREE.Vector3(); + normal = new THREE.Vector3(); + position2 = new THREE.Vector3(); + + } + + // Safeguards if bevels are not enabled + + if ( ! bevelEnabled ) { + + bevelSegments = 0; + bevelThickness = 0; + bevelSize = 0; + + } + + // Variables initalization + + var ahole, h, hl; // looping of holes + var scope = this; + var bevelPoints = []; + + var shapesOffset = this.vertices.length; + + var shapePoints = shape.extractPoints( curveSegments ); + + var vertices = shapePoints.shape; + var holes = shapePoints.holes; + + var reverse = !THREE.Shape.Utils.isClockWise( vertices ) ; + + if ( reverse ) { + + vertices = vertices.reverse(); + + // Maybe we should also check if holes are in the opposite direction, just to be safe ... + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + + if ( THREE.Shape.Utils.isClockWise( ahole ) ) { + + holes[ h ] = ahole.reverse(); + + } + + } + + reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)! + + } + + + var faces = THREE.Shape.Utils.triangulateShape ( vertices, holes ); + + /* Vertices */ + + var contour = vertices; // vertices has all points but contour has only points of circumference + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + + vertices = vertices.concat( ahole ); + + } + + + function scalePt2 ( pt, vec, size ) { + + if ( !vec ) return THREE.onerror( "die, vec not specified" ); + + return vec.clone().multiplyScalar( size ).add( pt ); + + } + + var b, bs, t, z, + vert, vlen = vertices.length, + face, flen = faces.length, + cont, clen = contour.length; + + + // Find directions for point movement + + var RAD_TO_DEGREES = 180 / Math.PI; + + + function getBevelVec( inPt, inPrev, inNext ) { + + var EPSILON = 0.0000000001; + var sign = THREE.Math.sign; + + // computes for inPt the corresponding point inPt' on a new contour + // shiftet by 1 unit (length of normalized vector) to the left + // if we walk along contour clockwise, this new contour is outside the old one + // + // inPt' is the intersection of the two lines parallel to the two + // adjacent edges of inPt at a distance of 1 unit on the left side. + + var v_trans_x, v_trans_y, shrink_by = 1; // resulting translation vector for inPt + + // good reading for geometry algorithms (here: line-line intersection) + // http://geomalgorithms.com/a05-_intersect-1.html + + var v_prev_x = inPt.x - inPrev.x, v_prev_y = inPt.y - inPrev.y; + var v_next_x = inNext.x - inPt.x, v_next_y = inNext.y - inPt.y; + + var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); + + // check for colinear edges + var colinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + + if ( Math.abs( colinear0 ) > EPSILON ) { // not colinear + + // length of vectors for normalizing + + var v_prev_len = Math.sqrt( v_prev_lensq ); + var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); + + // shift adjacent points by unit vectors to the left + + var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); + var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); + + var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); + var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); + + // scaling factor for v_prev to intersection point + + var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - + ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / + ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + + // vector from inPt to intersection point + + v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); + v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); + + // Don't normalize!, otherwise sharp corners become ugly + // but prevent crazy spikes + var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ) + if ( v_trans_lensq <= 2 ) { + return new THREE.Vector2( v_trans_x, v_trans_y ); + } else { + shrink_by = Math.sqrt( v_trans_lensq / 2 ); + } + + } else { // handle special case of colinear edges + + var direction_eq = false; // assumes: opposite + if ( v_prev_x > EPSILON ) { + if ( v_next_x > EPSILON ) { direction_eq = true; } + } else { + if ( v_prev_x < -EPSILON ) { + if ( v_next_x < -EPSILON ) { direction_eq = true; } + } else { + if ( sign(v_prev_y) == sign(v_next_y) ) { direction_eq = true; } + } + } + + if ( direction_eq ) { + // console.log("Warning: lines are a straight sequence"); + v_trans_x = -v_prev_y; + v_trans_y = v_prev_x; + shrink_by = Math.sqrt( v_prev_lensq ); + } else { + // console.log("Warning: lines are a straight spike"); + v_trans_x = v_prev_x; + v_trans_y = v_prev_y; + shrink_by = Math.sqrt( v_prev_lensq / 2 ); + } + + } + + return new THREE.Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); + + } + + + var contourMovements = []; + + for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + + if ( j === il ) j = 0; + if ( k === il ) k = 0; + + // (j)---(i)---(k) + // console.log('i,j,k', i, j , k) + + var pt_i = contour[ i ]; + var pt_j = contour[ j ]; + var pt_k = contour[ k ]; + + contourMovements[ i ]= getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); + + } + + var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + + oneHoleMovements = []; + + for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + + if ( j === il ) j = 0; + if ( k === il ) k = 0; + + // (j)---(i)---(k) + oneHoleMovements[ i ]= getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); + + } + + holesMovements.push( oneHoleMovements ); + verticesMovements = verticesMovements.concat( oneHoleMovements ); + + } + + + // Loop bevelSegments, 1 for the front, 1 for the back + + for ( b = 0; b < bevelSegments; b ++ ) { + //for ( b = bevelSegments; b > 0; b -- ) { + + t = b / bevelSegments; + z = bevelThickness * ( 1 - t ); + + //z = bevelThickness * t; + bs = bevelSize * ( Math.sin ( t * Math.PI/2 ) ) ; // curved + //bs = bevelSize * t ; // linear + + // contract shape + + for ( i = 0, il = contour.length; i < il; i ++ ) { + + vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + //vert = scalePt( contour[ i ], contourCentroid, bs, false ); + v( vert.x, vert.y, - z ); + + } + + // expand holes + + for ( h = 0, hl = holes.length; h < hl; h++ ) { + + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; + + for ( i = 0, il = ahole.length; i < il; i++ ) { + + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + //vert = scalePt( ahole[ i ], holesCentroids[ h ], bs, true ); + + v( vert.x, vert.y, -z ); + + } + + } + + } + + bs = bevelSize; + + // Back facing vertices + + for ( i = 0; i < vlen; i ++ ) { + + vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + + if ( !extrudeByPath ) { + + v( vert.x, vert.y, 0 ); + + } else { + + // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); + + normal.copy( splineTube.normals[0] ).multiplyScalar(vert.x); + binormal.copy( splineTube.binormals[0] ).multiplyScalar(vert.y); + + position2.copy( extrudePts[0] ).add(normal).add(binormal); + + v( position2.x, position2.y, position2.z ); + + } + + } + + // Add stepped vertices... + // Including front facing vertices + + var s; + + for ( s = 1; s <= steps; s ++ ) { + + for ( i = 0; i < vlen; i ++ ) { + + vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + + if ( !extrudeByPath ) { + + v( vert.x, vert.y, amount / steps * s ); + + } else { + + // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); + + normal.copy( splineTube.normals[s] ).multiplyScalar( vert.x ); + binormal.copy( splineTube.binormals[s] ).multiplyScalar( vert.y ); + + position2.copy( extrudePts[s] ).add( normal ).add( binormal ); + + v( position2.x, position2.y, position2.z ); + + } + + } + + } + + + // Add bevel segments planes + + //for ( b = 1; b <= bevelSegments; b ++ ) { + for ( b = bevelSegments - 1; b >= 0; b -- ) { + + t = b / bevelSegments; + z = bevelThickness * ( 1 - t ); + //bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) ); + bs = bevelSize * Math.sin ( t * Math.PI/2 ) ; + + // contract shape + + for ( i = 0, il = contour.length; i < il; i ++ ) { + + vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + v( vert.x, vert.y, amount + z ); + + } + + // expand holes + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + oneHoleMovements = holesMovements[ h ]; + + for ( i = 0, il = ahole.length; i < il; i ++ ) { + + vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + + if ( !extrudeByPath ) { + + v( vert.x, vert.y, amount + z ); + + } else { + + v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); + + } + + } + + } + + } + + /* Faces */ + + // Top and bottom faces + + buildLidFaces(); + + // Sides faces + + buildSideFaces(); + + + ///// Internal functions + + function buildLidFaces() { + + if ( bevelEnabled ) { + + var layer = 0 ; // steps + 1 + var offset = vlen * layer; + + // Bottom faces + + for ( i = 0; i < flen; i ++ ) { + + face = faces[ i ]; + f3( face[ 2 ]+ offset, face[ 1 ]+ offset, face[ 0 ] + offset, true ); + + } + + layer = steps + bevelSegments * 2; + offset = vlen * layer; + + // Top faces + + for ( i = 0; i < flen; i ++ ) { + + face = faces[ i ]; + f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset, false ); + + } + + } else { + + // Bottom faces + + for ( i = 0; i < flen; i++ ) { + + face = faces[ i ]; + f3( face[ 2 ], face[ 1 ], face[ 0 ], true ); + + } + + // Top faces + + for ( i = 0; i < flen; i ++ ) { + + face = faces[ i ]; + f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps, false ); + + } + } + + } + + // Create faces for the z-sides of the shape + + function buildSideFaces() { + + var layeroffset = 0; + sidewalls( contour, layeroffset ); + layeroffset += contour.length; + + for ( h = 0, hl = holes.length; h < hl; h ++ ) { + + ahole = holes[ h ]; + sidewalls( ahole, layeroffset ); + + //, true + layeroffset += ahole.length; + + } + + } + + function sidewalls( contour, layeroffset ) { + + var j, k; + i = contour.length; + + while ( --i >= 0 ) { + + j = i; + k = i - 1; + if ( k < 0 ) k = contour.length - 1; + + //console.log('b', i,j, i-1, k,vertices.length); + + var s = 0, sl = steps + bevelSegments * 2; + + for ( s = 0; s < sl; s ++ ) { + + var slen1 = vlen * s; + var slen2 = vlen * ( s + 1 ); + + var a = layeroffset + j + slen1, + b = layeroffset + k + slen1, + c = layeroffset + k + slen2, + d = layeroffset + j + slen2; + + f4( a, b, c, d, contour, s, sl, j, k ); + + } + } + + } + + + function v( x, y, z ) { + + scope.vertices.push( new THREE.Vector3( x, y, z ) ); + + } + + function f3( a, b, c, isBottom ) { + + a += shapesOffset; + b += shapesOffset; + c += shapesOffset; + + // normal, color, material + scope.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); + + var uvs = isBottom ? uvgen.generateBottomUV( scope, shape, options, a, b, c ) : uvgen.generateTopUV( scope, shape, options, a, b, c ); + + scope.faceVertexUvs[ 0 ].push( uvs ); + + } + + function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { + + a += shapesOffset; + b += shapesOffset; + c += shapesOffset; + d += shapesOffset; + + scope.faces.push( new THREE.Face3( a, b, d, null, null, extrudeMaterial ) ); + scope.faces.push( new THREE.Face3( b, c, d, null, null, extrudeMaterial ) ); + + var uvs = uvgen.generateSideWallUV( scope, shape, wallContour, options, a, b, c, d, + stepIndex, stepsLength, contourIndex1, contourIndex2 ); + + scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); + scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); + + } + +}; + +THREE.ExtrudeGeometry.WorldUVGenerator = { + + generateTopUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { + var ax = geometry.vertices[ indexA ].x, + ay = geometry.vertices[ indexA ].y, + + bx = geometry.vertices[ indexB ].x, + by = geometry.vertices[ indexB ].y, + + cx = geometry.vertices[ indexC ].x, + cy = geometry.vertices[ indexC ].y; + + return [ + new THREE.Vector2( ax, ay ), + new THREE.Vector2( bx, by ), + new THREE.Vector2( cx, cy ) + ]; + + }, + + generateBottomUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { + + return this.generateTopUV( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ); + + }, + + generateSideWallUV: function( geometry, extrudedShape, wallContour, extrudeOptions, + indexA, indexB, indexC, indexD, stepIndex, stepsLength, + contourIndex1, contourIndex2 ) { + + var ax = geometry.vertices[ indexA ].x, + ay = geometry.vertices[ indexA ].y, + az = geometry.vertices[ indexA ].z, + + bx = geometry.vertices[ indexB ].x, + by = geometry.vertices[ indexB ].y, + bz = geometry.vertices[ indexB ].z, + + cx = geometry.vertices[ indexC ].x, + cy = geometry.vertices[ indexC ].y, + cz = geometry.vertices[ indexC ].z, + + dx = geometry.vertices[ indexD ].x, + dy = geometry.vertices[ indexD ].y, + dz = geometry.vertices[ indexD ].z; + + if ( Math.abs( ay - by ) < 0.01 ) { + return [ + new THREE.Vector2( ax, 1 - az ), + new THREE.Vector2( bx, 1 - bz ), + new THREE.Vector2( cx, 1 - cz ), + new THREE.Vector2( dx, 1 - dz ) + ]; + } else { + return [ + new THREE.Vector2( ay, 1 - az ), + new THREE.Vector2( by, 1 - bz ), + new THREE.Vector2( cy, 1 - cz ), + new THREE.Vector2( dy, 1 - dz ) + ]; + } + } +}; + +THREE.ExtrudeGeometry.__v1 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v2 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v3 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v4 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v5 = new THREE.Vector2(); +THREE.ExtrudeGeometry.__v6 = new THREE.Vector2(); + +/** + * @author jonobr1 / http://jonobr1.com + * + * Creates a one-sided polygonal geometry from a path shape. Similar to + * ExtrudeGeometry. + * + * parameters = { + * + * curveSegments: , // number of points on the curves. NOT USED AT THE MOMENT. + * + * material: // material index for front and back faces + * uvGenerator: // object that provides UV generator functions + * + * } + **/ + +THREE.ShapeGeometry = function ( shapes, options ) { + + THREE.Geometry.call( this ); + this.className = "ShapeGeometry"; + + if ( shapes instanceof Array === false ) shapes = [ shapes ]; + + this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); + + this.addShapeList( shapes, options ); + + this.computeCentroids(); + this.computeFaceNormals(); + +}; + +THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * Add an array of shapes to THREE.ShapeGeometry. + */ +THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) { + + for ( var i = 0, l = shapes.length; i < l; i++ ) { + + this.addShape( shapes[ i ], options ); + + } + + return this; + +}; + +/** + * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry. + */ +THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { + + if ( options === undefined ) options = {}; + var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + + var material = options.material; + var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator; + + var shapebb = this.shapebb; + + // + + var i, l, hole, s; + + var shapesOffset = this.vertices.length; + var shapePoints = shape.extractPoints( curveSegments ); + + var vertices = shapePoints.shape; + var holes = shapePoints.holes; + + var reverse = !THREE.Shape.Utils.isClockWise( vertices ); + + if ( reverse ) { + + vertices = vertices.reverse(); + + // Maybe we should also check if holes are in the opposite direction, just to be safe... + + for ( i = 0, l = holes.length; i < l; i++ ) { + + hole = holes[ i ]; + + if ( THREE.Shape.Utils.isClockWise( hole ) ) { + + holes[ i ] = hole.reverse(); + + } + + } + + reverse = false; + + } + + var faces = THREE.Shape.Utils.triangulateShape( vertices, holes ); + + // Vertices + + var contour = vertices; + + for ( i = 0, l = holes.length; i < l; i++ ) { + + hole = holes[ i ]; + vertices = vertices.concat( hole ); + + } + + // + + var vert, vlen = vertices.length; + var face, flen = faces.length; + var cont, clen = contour.length; + + for ( i = 0; i < vlen; i++ ) { + + vert = vertices[ i ]; + + this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) ); + + } + + for ( i = 0; i < flen; i++ ) { + + face = faces[ i ]; + + var a = face[ 0 ] + shapesOffset; + var b = face[ 1 ] + shapesOffset; + var c = face[ 2 ] + shapesOffset; + + this.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); + this.faceVertexUvs[ 0 ].push( uvgen.generateBottomUV( this, shape, options, a, b, c ) ); + + } + +}; + +/** + * @author astrodud / http://astrodud.isgreat.org/ + * @author zz85 / https://github.com/zz85 + * @author bhouston / http://exocortex.com + */ + +// points - to create a closed torus, one must use a set of points +// like so: [ a, b, c, d, a ], see first is the same as last. +// segments - the number of circumference segments to create +// phiStart - the starting radian +// phiLength - the radian (0 to 2*PI) range of the lathed section +// 2*pi is a closed lathe, less than 2PI is a portion. +THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) { + + THREE.Geometry.call( this ); + this.className = "LatheGeometry"; + + segments = segments || 12; + phiStart = phiStart || 0; + phiLength = phiLength || 2 * Math.PI; + + var inversePointLength = 1.0 / ( points.length - 1 ); + var inverseSegments = 1.0 / segments; + + for ( var i = 0, il = segments; i <= il; i ++ ) { + + var phi = phiStart + i * inverseSegments * phiLength; + + var c = Math.cos( phi ), + s = Math.sin( phi ); + + for ( var j = 0, jl = points.length; j < jl; j ++ ) { + + var pt = points[ j ]; + + var vertex = new THREE.Vector3(); + + vertex.x = c * pt.x - s * pt.y; + vertex.y = s * pt.x + c * pt.y; + vertex.z = pt.z; + + this.vertices.push( vertex ); + + } + + } + + var np = points.length; + + for ( var i = 0, il = segments; i < il; i ++ ) { + + for ( var j = 0, jl = points.length - 1; j < jl; j ++ ) { + + var base = j + np * i; + var a = base; + var b = base + np; + var c = base + 1 + np; + var d = base + 1; + + var u0 = i * inverseSegments; + var v0 = j * inversePointLength; + var u1 = u0 + inverseSegments; + var v1 = v0 + inversePointLength; + + this.faces.push( new THREE.Face3( a, b, d ) ); + + this.faceVertexUvs[ 0 ].push( [ + + new THREE.Vector2( u0, v0 ), + new THREE.Vector2( u1, v0 ), + new THREE.Vector2( u0, v1 ) + + ] ); + + this.faces.push( new THREE.Face3( b, c, d ) ); + + this.faceVertexUvs[ 0 ].push( [ + + new THREE.Vector2( u1, v0 ), + new THREE.Vector2( u1, v1 ), + new THREE.Vector2( u0, v1 ) + + ] ); + + + } + + } + + this.mergeVertices(); + this.computeCentroids(); + this.computeFaceNormals(); + this.computeVertexNormals(); + +}; + +THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author mrdoob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as + */ + +THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) { + + THREE.Geometry.call( this ); + this.className = "PlaneGeometry"; + + this.width = width; + this.height = height; + + this.widthSegments = widthSegments || 1; + this.heightSegments = heightSegments || 1; + + var ix, iz; + var width_half = width / 2; + var height_half = height / 2; + + var gridX = this.widthSegments; + var gridZ = this.heightSegments; + + var gridX1 = gridX + 1; + var gridZ1 = gridZ + 1; + + var segment_width = this.width / gridX; + var segment_height = this.height / gridZ; + + var normal = new THREE.Vector3( 0, 0, 1 ); + + for ( iz = 0; iz < gridZ1; iz ++ ) { + + for ( ix = 0; ix < gridX1; ix ++ ) { + + var x = ix * segment_width - width_half; + var y = iz * segment_height - height_half; + + this.vertices.push( new THREE.Vector3( x, - y, 0 ) ); + + } + + } + + for ( iz = 0; iz < gridZ; iz ++ ) { + + for ( ix = 0; ix < gridX; ix ++ ) { + + var a = ix + gridX1 * iz; + var b = ix + gridX1 * ( iz + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iz + 1 ); + var d = ( ix + 1 ) + gridX1 * iz; + + var uva = new THREE.Vector2( ix / gridX, 1 - iz / gridZ ); + var uvb = new THREE.Vector2( ix / gridX, 1 - ( iz + 1 ) / gridZ ); + var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iz + 1 ) / gridZ ); + var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iz / gridZ ); + + var face = new THREE.Face3( a, b, d ); + face.normal.copy( normal ); + face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); + + this.faces.push( face ); + this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); + + face = new THREE.Face3( b, c, d ); + face.normal.copy( normal ); + face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); + + this.faces.push( face ); + this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); + + } + + } + + this.computeCentroids(); + +}; + +THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author Kaleb Murphy + */ + +THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { + + THREE.Geometry.call( this ); + this.className = "RingGeometry"; + + innerRadius = innerRadius || 0; + outerRadius = outerRadius || 50; + + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + + thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; + phiSegments = phiSegments !== undefined ? Math.max( 3, phiSegments ) : 8; + + var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); + + for ( i = 0; i <= phiSegments; i ++ ) { // concentric circles inside ring + + for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle + + var vertex = new THREE.Vector3(); + var segment = thetaStart + o / thetaSegments * thetaLength; + + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); + + this.vertices.push( vertex ); + uvs.push( new THREE.Vector2( ( vertex.x / outerRadius + 1 ) / 2, ( vertex.y / outerRadius + 1 ) / 2 ) ); + } + + radius += radiusStep; + + } + + var n = new THREE.Vector3( 0, 0, 1 ); + + for ( i = 0; i < phiSegments; i ++ ) { // concentric circles inside ring + + var thetaSegment = i * thetaSegments; + + for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle + + var segment = o + thetaSegment; + + var v1 = segment + i; + var v2 = segment + thetaSegments + i; + var v3 = segment + thetaSegments + 1 + i; + + this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); + + v1 = segment + i; + v2 = segment + thetaSegments + 1 + i; + v3 = segment + 1 + i; + + this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); + + } + } + + this.computeCentroids(); + this.computeFaceNormals(); + + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + +}; + +THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { + + THREE.Geometry.call( this ); + this.className = "SphereGeometry"; + + this.radius = radius = radius || 50; + + this.widthSegments = widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); + this.heightSegments = heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); + + this.phiStart = phiStart = phiStart !== undefined ? phiStart : 0; + this.phiLength = phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; + + this.thetaStart = thetaStart = thetaStart !== undefined ? thetaStart : 0; + this.thetaLength = thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; + + var x, y, vertices = [], uvs = []; + + for ( y = 0; y <= heightSegments; y ++ ) { + + var verticesRow = []; + var uvsRow = []; + + for ( x = 0; x <= widthSegments; x ++ ) { + + var u = x / widthSegments; + var v = y / heightSegments; + + var vertex = new THREE.Vector3(); + vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); + vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); + + this.vertices.push( vertex ); + + verticesRow.push( this.vertices.length - 1 ); + uvsRow.push( new THREE.Vector2( u, 1 - v ) ); + + } + + vertices.push( verticesRow ); + uvs.push( uvsRow ); + + } + + for ( y = 0; y < this.heightSegments; y ++ ) { + + for ( x = 0; x < this.widthSegments; x ++ ) { + + var v1 = vertices[ y ][ x + 1 ]; + var v2 = vertices[ y ][ x ]; + var v3 = vertices[ y + 1 ][ x ]; + var v4 = vertices[ y + 1 ][ x + 1 ]; + + var n1 = this.vertices[ v1 ].clone().normalize(); + var n2 = this.vertices[ v2 ].clone().normalize(); + var n3 = this.vertices[ v3 ].clone().normalize(); + var n4 = this.vertices[ v4 ].clone().normalize(); + + var uv1 = uvs[ y ][ x + 1 ].clone(); + var uv2 = uvs[ y ][ x ].clone(); + var uv3 = uvs[ y + 1 ][ x ].clone(); + var uv4 = uvs[ y + 1 ][ x + 1 ].clone(); + + if ( Math.abs( this.vertices[ v1 ].y ) === this.radius ) { + + uv1.x = ( uv1.x + uv2.x ) / 2; + this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] ); + + } else if ( Math.abs( this.vertices[ v3 ].y ) === this.radius ) { + + uv3.x = ( uv3.x + uv4.x ) / 2; + this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); + + } else { + + this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); + + this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); + this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); + + } + + } + + } + + this.computeCentroids(); + this.computeFaceNormals(); + + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + +}; + +THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * @author alteredq / http://alteredqualia.com/ + * + * For creating 3D text geometry in three.js + * + * Text = 3D Text + * + * parameters = { + * size: , // size of the text + * height: , // thickness to extrude text + * curveSegments: , // number of points on the curves + * + * font: , // font name + * weight: , // font weight (normal, bold) + * style: , // font style (normal, italics) + * + * bevelEnabled: , // turn on bevel + * bevelThickness: , // how deep into text bevel goes + * bevelSize: , // how far from text outline is bevel + * } + * + */ + +/* Usage Examples + + // TextGeometry wrapper + + var text3d = new TextGeometry( text, options ); + + // Complete manner + + var textShapes = THREE.FontUtils.generateShapes( text, options ); + var text3d = new ExtrudeGeometry( textShapes, options ); + +*/ + + +THREE.TextGeometry = function ( text, parameters ) { + this.className = "TextGeometry"; + + parameters = parameters || {}; + + var textShapes = THREE.FontUtils.generateShapes( text, parameters ); + + // translate parameters to ExtrudeGeometry API + + parameters.amount = parameters.height !== undefined ? parameters.height : 50; + + // defaults + + if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; + if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; + if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; + + THREE.ExtrudeGeometry.call( this, textShapes, parameters ); + +}; + +THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype ); + +/** + * @author oosmoxiecode + * @author mrdoob / http://mrdoob.com/ + * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888 + */ + +THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) { + + THREE.Geometry.call( this ); + this.className = "TorusGeometry"; + + var scope = this; + + this.radius = radius || 100; + this.tube = tube || 40; + this.radialSegments = radialSegments || 8; + this.tubularSegments = tubularSegments || 6; + this.arc = arc || Math.PI * 2; + + var center = new THREE.Vector3(), uvs = [], normals = []; + + for ( var j = 0; j <= this.radialSegments; j ++ ) { + + for ( var i = 0; i <= this.tubularSegments; i ++ ) { + + var u = i / this.tubularSegments * this.arc; + var v = j / this.radialSegments * Math.PI * 2; + + center.x = this.radius * Math.cos( u ); + center.y = this.radius * Math.sin( u ); + + var vertex = new THREE.Vector3(); + vertex.x = ( this.radius + this.tube * Math.cos( v ) ) * Math.cos( u ); + vertex.y = ( this.radius + this.tube * Math.cos( v ) ) * Math.sin( u ); + vertex.z = this.tube * Math.sin( v ); + + this.vertices.push( vertex ); + + uvs.push( new THREE.Vector2( i / this.tubularSegments, j / this.radialSegments ) ); + normals.push( vertex.clone().sub( center ).normalize() ); + + } + + } + + + for ( var j = 1; j <= this.radialSegments; j ++ ) { + + for ( var i = 1; i <= this.tubularSegments; i ++ ) { + + var a = ( this.tubularSegments + 1 ) * j + i - 1; + var b = ( this.tubularSegments + 1 ) * ( j - 1 ) + i - 1; + var c = ( this.tubularSegments + 1 ) * ( j - 1 ) + i; + var d = ( this.tubularSegments + 1 ) * j + i; + + var face = new THREE.Face3( a, b, d, [ normals[ a ].clone(), normals[ b ].clone(), normals[ d ].clone() ] ); + this.faces.push( face ); + this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ d ].clone() ] ); + + face = new THREE.Face3( b, c, d, [ normals[ b ].clone(), normals[ c ].clone(), normals[ d ].clone() ] ); + this.faces.push( face ); + this.faceVertexUvs[ 0 ].push( [ uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] ); + + } + + } + + this.computeCentroids(); + this.computeFaceNormals(); + +}; + +THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author oosmoxiecode + * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473 + */ + +THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) { + + THREE.Geometry.call( this ); + this.className = "TorusKnotGeometry"; + + var scope = this; + + this.radius = radius || 100; + this.tube = tube || 40; + this.radialSegments = radialSegments || 64; + this.tubularSegments = tubularSegments || 8; + this.p = p || 2; + this.q = q || 3; + this.heightScale = heightScale || 1; + this.grid = new Array( this.radialSegments ); + + var tang = new THREE.Vector3(); + var n = new THREE.Vector3(); + var bitan = new THREE.Vector3(); + + for ( var i = 0; i < this.radialSegments; ++ i ) { + + this.grid[ i ] = new Array( this.tubularSegments ); + var u = i / this.radialSegments * 2 * this.p * Math.PI; + var p1 = getPos( u, this.q, this.p, this.radius, this.heightScale ); + var p2 = getPos( u + 0.01, this.q, this.p, this.radius, this.heightScale ); + tang.subVectors( p2, p1 ); + n.addVectors( p2, p1 ); + + bitan.crossVectors( tang, n ); + n.crossVectors( bitan, tang ); + bitan.normalize(); + n.normalize(); + + for ( var j = 0; j < this.tubularSegments; ++ j ) { + + var v = j / this.tubularSegments * 2 * Math.PI; + var cx = - this.tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. + var cy = this.tube * Math.sin( v ); + + var pos = new THREE.Vector3(); + pos.x = p1.x + cx * n.x + cy * bitan.x; + pos.y = p1.y + cx * n.y + cy * bitan.y; + pos.z = p1.z + cx * n.z + cy * bitan.z; + + this.grid[ i ][ j ] = scope.vertices.push( pos ) - 1; + + } + + } + + for ( var i = 0; i < this.radialSegments; ++ i ) { + + for ( var j = 0; j < this.tubularSegments; ++ j ) { + + var ip = ( i + 1 ) % this.radialSegments; + var jp = ( j + 1 ) % this.tubularSegments; + + var a = this.grid[ i ][ j ]; + var b = this.grid[ ip ][ j ]; + var c = this.grid[ ip ][ jp ]; + var d = this.grid[ i ][ jp ]; + + var uva = new THREE.Vector2( i / this.radialSegments, j / this.tubularSegments ); + var uvb = new THREE.Vector2( ( i + 1 ) / this.radialSegments, j / this.tubularSegments ); + var uvc = new THREE.Vector2( ( i + 1 ) / this.radialSegments, ( j + 1 ) / this.tubularSegments ); + var uvd = new THREE.Vector2( i / this.radialSegments, ( j + 1 ) / this.tubularSegments ); + + this.faces.push( new THREE.Face3( a, b, d ) ); + this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); + + this.faces.push( new THREE.Face3( b, c, d ) ); + this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); + + } + } + + this.computeCentroids(); + this.computeFaceNormals(); + this.computeVertexNormals(); + + function getPos( u, in_q, in_p, radius, heightScale ) { + + var cu = Math.cos( u ); + var su = Math.sin( u ); + var quOverP = in_q / in_p * u; + var cs = Math.cos( quOverP ); + + var tx = radius * ( 2 + cs ) * 0.5 * cu; + var ty = radius * ( 2 + cs ) * su * 0.5; + var tz = heightScale * radius * Math.sin( quOverP ) * 0.5; + + return new THREE.Vector3( tx, ty, tz ); + + } + +}; + +THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author WestLangley / https://github.com/WestLangley + * @author zz85 / https://github.com/zz85 + * @author miningold / https://github.com/miningold + * + * Modified from the TorusKnotGeometry by @oosmoxiecode + * + * Creates a tube which extrudes along a 3d spline + * + * Uses parallel transport frames as described in + * http://www.cs.indiana.edu/pub/techreports/TR425.pdf + */ + +THREE.TubeGeometry = function( path, segments, radius, radialSegments, closed ) { + + THREE.Geometry.call( this ); + this.className = "TubeGeometry"; + + this.path = path; + this.segments = segments || 64; + this.radius = radius || 1; + this.radialSegments = radialSegments || 8; + this.closed = closed || false; + + this.grid = []; + + var scope = this, + + tangent, + normal, + binormal, + + numpoints = this.segments + 1, + + x, y, z, + tx, ty, tz, + u, v, + + cx, cy, + pos, pos2 = new THREE.Vector3(), + i, j, + ip, jp, + a, b, c, d, + uva, uvb, uvc, uvd; + + var frames = new THREE.TubeGeometry.FrenetFrames( this.path, this.segments, this.closed ), + tangents = frames.tangents, + normals = frames.normals, + binormals = frames.binormals; + + // proxy internals + this.tangents = tangents; + this.normals = normals; + this.binormals = binormals; + + function vert( x, y, z ) { + + return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1; + + } + + + // consruct the grid + + for ( i = 0; i < numpoints; i++ ) { + + this.grid[ i ] = []; + + u = i / ( numpoints - 1 ); + + pos = path.getPointAt( u ); + + tangent = tangents[ i ]; + normal = normals[ i ]; + binormal = binormals[ i ]; + + for ( j = 0; j < this.radialSegments; j++ ) { + + v = j / this.radialSegments * 2 * Math.PI; + + cx = -this.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. + cy = this.radius * Math.sin( v ); + + pos2.copy( pos ); + pos2.x += cx * normal.x + cy * binormal.x; + pos2.y += cx * normal.y + cy * binormal.y; + pos2.z += cx * normal.z + cy * binormal.z; + + this.grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z ); + + } + } + + + // construct the mesh + + for ( i = 0; i < this.segments; i++ ) { + + for ( j = 0; j < this.radialSegments; j++ ) { + + ip = ( this.closed ) ? (i + 1) % this.segments : i + 1; + jp = (j + 1) % this.radialSegments; + + a = this.grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! *** + b = this.grid[ ip ][ j ]; + c = this.grid[ ip ][ jp ]; + d = this.grid[ i ][ jp ]; + + uva = new THREE.Vector2( i / this.segments, j / this.radialSegments ); + uvb = new THREE.Vector2( ( i + 1 ) / this.segments, j / this.radialSegments ); + uvc = new THREE.Vector2( ( i + 1 ) / this.segments, ( j + 1 ) / this.radialSegments ); + uvd = new THREE.Vector2( i / this.segments, ( j + 1 ) / this.radialSegments ); + + this.faces.push( new THREE.Face3( a, b, d ) ); + this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); + + this.faces.push( new THREE.Face3( b, c, d ) ); + this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); + + } + } + + this.computeCentroids(); + this.computeFaceNormals(); + this.computeVertexNormals(); + +}; + +THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); + + +// For computing of Frenet frames, exposing the tangents, normals and binormals the spline +THREE.TubeGeometry.FrenetFrames = function(path, segments, closed) { + + var tangent = new THREE.Vector3(), + normal = new THREE.Vector3(), + binormal = new THREE.Vector3(), + + tangents = [], + normals = [], + binormals = [], + + vec = new THREE.Vector3(), + mat = new THREE.Matrix4(), + + numpoints = segments + 1, + theta, + epsilon = 0.0001, + smallest, + + tx, ty, tz, + i, u, v; + + + // expose internals + this.tangents = tangents; + this.normals = normals; + this.binormals = binormals; + + // compute the tangent vectors for each segment on the path + + for ( i = 0; i < numpoints; i++ ) { + + u = i / ( numpoints - 1 ); + + tangents[ i ] = path.getTangentAt( u ); + tangents[ i ].normalize(); + + } + + initialNormal3(); + + function initialNormal1(lastBinormal) { + // fixed start binormal. Has dangers of 0 vectors + normals[ 0 ] = new THREE.Vector3(); + binormals[ 0 ] = new THREE.Vector3(); + if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 ); + normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize(); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); + } + + function initialNormal2() { + + // This uses the Frenet-Serret formula for deriving binormal + var t2 = path.getTangentAt( epsilon ); + + normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize(); + binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] ); + + normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); + + } + + function initialNormal3() { + // select an initial normal vector perpenicular to the first tangent vector, + // and in the direction of the smallest tangent xyz component + + normals[ 0 ] = new THREE.Vector3(); + binormals[ 0 ] = new THREE.Vector3(); + smallest = Number.MAX_VALUE; + tx = Math.abs( tangents[ 0 ].x ); + ty = Math.abs( tangents[ 0 ].y ); + tz = Math.abs( tangents[ 0 ].z ); + + if ( tx <= smallest ) { + smallest = tx; + normal.set( 1, 0, 0 ); + } + + if ( ty <= smallest ) { + smallest = ty; + normal.set( 0, 1, 0 ); + } + + if ( tz <= smallest ) { + normal.set( 0, 0, 1 ); + } + + vec.crossVectors( tangents[ 0 ], normal ).normalize(); + + normals[ 0 ].crossVectors( tangents[ 0 ], vec ); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); + } + + + // compute the slowly-varying normal and binormal vectors for each segment on the path + + for ( i = 1; i < numpoints; i++ ) { + + normals[ i ] = normals[ i-1 ].clone(); + + binormals[ i ] = binormals[ i-1 ].clone(); + + vec.crossVectors( tangents[ i-1 ], tangents[ i ] ); + + if ( vec.length() > epsilon ) { + + vec.normalize(); + + theta = Math.acos( THREE.Math.clamp( tangents[ i-1 ].dot( tangents[ i ] ), -1, 1 ) ); // clamp for floating pt errors + + normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); + + } + + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + + } + + + // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same + + if ( closed ) { + + theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints-1 ] ), -1, 1 ) ); + theta /= ( numpoints - 1 ); + + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints-1 ] ) ) > 0 ) { + + theta = -theta; + + } + + for ( i = 1; i < numpoints; i++ ) { + + // twist a little... + normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + + } + + } +}; + +/** + * @author clockworkgeek / https://github.com/clockworkgeek + * @author timothypratley / https://github.com/timothypratley + * @author WestLangley / http://github.com/WestLangley +*/ + +THREE.PolyhedronGeometry = function ( vertices, faces, radius, detail ) { + + THREE.Geometry.call( this ); + this.className = "PolyhedronGeometry"; + + radius = radius || 1; + detail = detail || 0; + + var that = this; + + for ( var i = 0, l = vertices.length; i < l; i ++ ) { + + prepare( new THREE.Vector3( vertices[ i ][ 0 ], vertices[ i ][ 1 ], vertices[ i ][ 2 ] ) ); + + } + + var midpoints = [], p = this.vertices; + + var f = []; + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + var v1 = p[ faces[ i ][ 0 ] ]; + var v2 = p[ faces[ i ][ 1 ] ]; + var v3 = p[ faces[ i ][ 2 ] ]; + + f[ i ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); + + } + + for ( var i = 0, l = f.length; i < l; i ++ ) { + + subdivide(f[ i ], detail); + + } + + + // Handle case when face straddles the seam + + for ( var i = 0, l = this.faceVertexUvs[ 0 ].length; i < l; i ++ ) { + + var uvs = this.faceVertexUvs[ 0 ][ i ]; + + var x0 = uvs[ 0 ].x; + var x1 = uvs[ 1 ].x; + var x2 = uvs[ 2 ].x; + + var max = Math.max( x0, Math.max( x1, x2 ) ); + var min = Math.min( x0, Math.min( x1, x2 ) ); + + if ( max > 0.9 && min < 0.1 ) { // 0.9 is somewhat arbitrary + + if ( x0 < 0.2 ) uvs[ 0 ].x += 1; + if ( x1 < 0.2 ) uvs[ 1 ].x += 1; + if ( x2 < 0.2 ) uvs[ 2 ].x += 1; + + } + + } + + + // Apply radius + + for ( var i = 0, l = this.vertices.length; i < l; i ++ ) { + + this.vertices[ i ].multiplyScalar( radius ); + + } + + + // Merge vertices + + this.mergeVertices(); + + this.computeCentroids(); + + this.computeFaceNormals(); + + this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); + + + // Project vector onto sphere's surface + + function prepare( vector ) { + + var vertex = vector.normalize().clone(); + vertex.index = that.vertices.push( vertex ) - 1; + + // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle. + + var u = azimuth( vector ) / 2 / Math.PI + 0.5; + var v = inclination( vector ) / Math.PI + 0.5; + vertex.uv = new THREE.Vector2( u, 1 - v ); + + return vertex; + + } + + + // Approximate a curved face with recursively sub-divided triangles. + + function make( v1, v2, v3 ) { + + var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); + face.centroid.add( v1 ).add( v2 ).add( v3 ).divideScalar( 3 ); + that.faces.push( face ); + + var azi = azimuth( face.centroid ); + + that.faceVertexUvs[ 0 ].push( [ + correctUV( v1.uv, v1, azi ), + correctUV( v2.uv, v2, azi ), + correctUV( v3.uv, v3, azi ) + ] ); + + } + + + // Analytically subdivide a face to the required detail level. + + function subdivide(face, detail ) { + + var cols = Math.pow(2, detail); + var cells = Math.pow(4, detail); + var a = prepare( that.vertices[ face.a ] ); + var b = prepare( that.vertices[ face.b ] ); + var c = prepare( that.vertices[ face.c ] ); + var v = []; + + // Construct all of the vertices for this subdivision. + + for ( var i = 0 ; i <= cols; i ++ ) { + + v[ i ] = []; + + var aj = prepare( a.clone().lerp( c, i / cols ) ); + var bj = prepare( b.clone().lerp( c, i / cols ) ); + var rows = cols - i; + + for ( var j = 0; j <= rows; j ++) { + + if ( j == 0 && i == cols ) { + + v[ i ][ j ] = aj; + + } else { + + v[ i ][ j ] = prepare( aj.clone().lerp( bj, j / rows ) ); + + } + + } + + } + + // Construct all of the faces. + + for ( var i = 0; i < cols ; i ++ ) { + + for ( var j = 0; j < 2 * (cols - i) - 1; j ++ ) { + + var k = Math.floor( j / 2 ); + + if ( j % 2 == 0 ) { + + make( + v[ i ][ k + 1], + v[ i + 1 ][ k ], + v[ i ][ k ] + ); + + } else { + + make( + v[ i ][ k + 1 ], + v[ i + 1][ k + 1], + v[ i + 1 ][ k ] + ); + + } + + } + + } + + } + + + // Angle around the Y axis, counter-clockwise when looking from above. + + function azimuth( vector ) { + + return Math.atan2( vector.z, -vector.x ); + + } + + + // Angle above the XZ plane. + + function inclination( vector ) { + + return Math.atan2( -vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); + + } + + + // Texture fixing helper. Spheres have some odd behaviours. + + function correctUV( uv, vector, azimuth ) { + + if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) uv = new THREE.Vector2( uv.x - 1, uv.y ); + if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.Vector2( azimuth / 2 / Math.PI + 0.5, uv.y ); + return uv.clone(); + + } + + +}; + +THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author timothypratley / https://github.com/timothypratley + */ + +THREE.IcosahedronGeometry = function ( radius, detail ) { + + this.radius = radius; + this.detail = detail; + + var t = ( 1 + Math.sqrt( 5 ) ) / 2; + + var vertices = [ + [ -1, t, 0 ], [ 1, t, 0 ], [ -1, -t, 0 ], [ 1, -t, 0 ], + [ 0, -1, t ], [ 0, 1, t ], [ 0, -1, -t ], [ 0, 1, -t ], + [ t, 0, -1 ], [ t, 0, 1 ], [ -t, 0, -1 ], [ -t, 0, 1 ] + ]; + + var faces = [ + [ 0, 11, 5 ], [ 0, 5, 1 ], [ 0, 1, 7 ], [ 0, 7, 10 ], [ 0, 10, 11 ], + [ 1, 5, 9 ], [ 5, 11, 4 ], [ 11, 10, 2 ], [ 10, 7, 6 ], [ 7, 1, 8 ], + [ 3, 9, 4 ], [ 3, 4, 2 ], [ 3, 2, 6 ], [ 3, 6, 8 ], [ 3, 8, 9 ], + [ 4, 9, 5 ], [ 2, 4, 11 ], [ 6, 2, 10 ], [ 8, 6, 7 ], [ 9, 8, 1 ] + ]; + + THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); + this.className = "IcosahedronGeometry"; + +}; + +THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author timothypratley / https://github.com/timothypratley + */ + +THREE.OctahedronGeometry = function ( radius, detail ) { + + var vertices = [ + [ 1, 0, 0 ], [ -1, 0, 0 ], [ 0, 1, 0 ], [ 0, -1, 0 ], [ 0, 0, 1 ], [ 0, 0, -1 ] + ]; + + var faces = [ + [ 0, 2, 4 ], [ 0, 4, 3 ], [ 0, 3, 5 ], [ 0, 5, 2 ], [ 1, 2, 5 ], [ 1, 5, 3 ], [ 1, 3, 4 ], [ 1, 4, 2 ] + ]; + + THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); + this.className = "OctahedronGeometry"; + +}; + +THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author timothypratley / https://github.com/timothypratley + */ + +THREE.TetrahedronGeometry = function ( radius, detail ) { + this.className = "TetrahedronGeometry"; + + var vertices = [ + [ 1, 1, 1 ], [ -1, -1, 1 ], [ -1, 1, -1 ], [ 1, -1, -1 ] + ]; + + var faces = [ + [ 2, 1, 0 ], [ 0, 3, 2 ], [ 1, 3, 0 ], [ 2, 3, 1 ] + ]; + + THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); + +}; + +THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author zz85 / https://github.com/zz85 + * Parametric Surfaces Geometry + * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 + * + * new THREE.ParametricGeometry( parametricFunction, uSegments, ySegements ); + * + */ + +THREE.ParametricGeometry = function ( func, slices, stacks ) { + + THREE.Geometry.call( this ); + this.className = "ParametricGeometry"; + + var verts = this.vertices; + var faces = this.faces; + var uvs = this.faceVertexUvs[ 0 ]; + + var i, il, j, p; + var u, v; + + var stackCount = stacks + 1; + var sliceCount = slices + 1; + + for ( i = 0; i <= stacks; i ++ ) { + + v = i / stacks; + + for ( j = 0; j <= slices; j ++ ) { + + u = j / slices; + + p = func( u, v ); + verts.push( p ); + + } + } + + var a, b, c, d; + var uva, uvb, uvc, uvd; + + for ( i = 0; i < stacks; i ++ ) { + + for ( j = 0; j < slices; j ++ ) { + + a = i * sliceCount + j; + b = i * sliceCount + j + 1; + c = (i + 1) * sliceCount + j + 1; + d = (i + 1) * sliceCount + j; + + uva = new THREE.Vector2( j / slices, i / stacks ); + uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks ); + uvc = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks ); + uvd = new THREE.Vector2( j / slices, ( i + 1 ) / stacks ); + + faces.push( new THREE.Face3( a, b, d ) ); + uvs.push( [ uva, uvb, uvd ] ); + + faces.push( new THREE.Face3( b, c, d ) ); + uvs.push( [ uvb.clone(), uvc, uvd.clone() ] ); + + } + + } + + // console.log(this); + + // magic bullet + // var diff = this.mergeVertices(); + // console.log('removed ', diff, ' vertices by merging'); + + this.computeCentroids(); + this.computeFaceNormals(); + this.computeVertexNormals(); + +}; + +THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype ); + +/** + * @author sroucheray / http://sroucheray.org/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.AxisHelper = function ( size ) { + + size = size || 1; + + var geometry = new THREE.Geometry(); + + geometry.vertices.push( + new THREE.Vector3(), new THREE.Vector3( size, 0, 0 ), + new THREE.Vector3(), new THREE.Vector3( 0, size, 0 ), + new THREE.Vector3(), new THREE.Vector3( 0, 0, size ) + ); + + geometry.colors.push( + new THREE.Color( 0xff0000 ), new THREE.Color( 0xffaa00 ), + new THREE.Color( 0x00ff00 ), new THREE.Color( 0xaaff00 ), + new THREE.Color( 0x0000ff ), new THREE.Color( 0x00aaff ) + ); + + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); + + THREE.Line.call( this, geometry, material, THREE.LinePieces ); + this.className = "AxisHelper"; + +}; + +THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype ); + +/** + * @author WestLangley / http://github.com/WestLangley + * @author zz85 / http://github.com/zz85 + * @author bhouston / http://exocortex.com + * + * Creates an arrow for visualizing directions + * + * Parameters: + * dir - Vector3 + * origin - Vector3 + * length - Number + * hex - color in hex value + * headLength - Number + * headWidth - Number + */ + +THREE.ArrowHelper = function ( dir, origin, length, hex, headLength, headWidth ) { + + // dir is assumed to be normalized + + THREE.Object3D.call( this ); + this.className = "ArrowHelper"; + + if ( hex === undefined ) hex = 0xffff00; + if ( length === undefined ) length = 1; + if ( headLength === undefined ) headLength = 0.2 * length; + if ( headWidth === undefined ) headWidth = 0.2 * headLength; + + this.position = origin; + + var lineGeometry = new THREE.Geometry(); + lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ) ); + lineGeometry.vertices.push( new THREE.Vector3( 0, 1, 0 ) ); + + this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: hex } ) ); + this.line.matrixAutoUpdate = false; + this.add( this.line ); + + var coneGeometry = new THREE.CylinderGeometry( 0, 0.5, 1, 5, 1 ); + coneGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) ); + + this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: hex } ) ); + this.cone.matrixAutoUpdate = false; + this.add( this.cone ); + + this.setDirection( dir ); + this.setLength( length, headLength, headWidth ); + +}; + +THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.ArrowHelper.prototype.setDirection = function () { + + var axis = new THREE.Vector3(); + var radians; + + return function ( dir ) { + + // dir is assumed to be normalized + + if ( dir.y > 0.99999 ) { + + this.quaternion.set( 0, 0, 0, 1 ); + + } else if ( dir.y < - 0.99999 ) { + + this.quaternion.set( 1, 0, 0, 0 ); + + } else { + + axis.set( dir.z, 0, - dir.x ).normalize(); + + radians = Math.acos( dir.y ); + + this.quaternion.setFromAxisAngle( axis, radians ); + + } + + }; + +}(); + +THREE.ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { + + if ( headLength === undefined ) headLength = 0.2 * length; + if ( headWidth === undefined ) headWidth = 0.2 * headLength; + + this.line.scale.set( 1, length, 1 ); + this.line.updateMatrix(); + + this.cone.scale.set( headWidth, headLength, headWidth ); + this.cone.position.y = length; + this.cone.updateMatrix(); + +}; + +THREE.ArrowHelper.prototype.setColor = function ( hex ) { + + this.line.material.color.setHex( hex ); + this.cone.material.color.setHex( hex ); + +}; + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.BoxHelper = function ( object ) { + + // 5____4 + // 1/___0/| + // | 6__|_7 + // 2/___3/ + + var vertices = [ + new THREE.Vector3( 1, 1, 1 ), + new THREE.Vector3( - 1, 1, 1 ), + new THREE.Vector3( - 1, - 1, 1 ), + new THREE.Vector3( 1, - 1, 1 ), + + new THREE.Vector3( 1, 1, - 1 ), + new THREE.Vector3( - 1, 1, - 1 ), + new THREE.Vector3( - 1, - 1, - 1 ), + new THREE.Vector3( 1, - 1, - 1 ) + ]; + + this.vertices = vertices; + + // TODO: Wouldn't be nice if Line had .segments? + + var geometry = new THREE.Geometry(); + geometry.vertices.push( + vertices[ 0 ], vertices[ 1 ], + vertices[ 1 ], vertices[ 2 ], + vertices[ 2 ], vertices[ 3 ], + vertices[ 3 ], vertices[ 0 ], + + vertices[ 4 ], vertices[ 5 ], + vertices[ 5 ], vertices[ 6 ], + vertices[ 6 ], vertices[ 7 ], + vertices[ 7 ], vertices[ 4 ], + + vertices[ 0 ], vertices[ 4 ], + vertices[ 1 ], vertices[ 5 ], + vertices[ 2 ], vertices[ 6 ], + vertices[ 3 ], vertices[ 7 ] + ); + + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: 0xffff00 } ), THREE.LinePieces ); + + if ( object !== undefined ) { + + this.update( object ); + + } + +}; + +THREE.BoxHelper.prototype = Object.create( THREE.Line.prototype ); + +THREE.BoxHelper.prototype.update = function ( object ) { + + var geometry = object.geometry; + + if ( geometry.boundingBox === null ) { + + geometry.computeBoundingBox(); + + } + + var min = geometry.boundingBox.min; + var max = geometry.boundingBox.max; + var vertices = this.vertices; + + vertices[ 0 ].set( max.x, max.y, max.z ); + vertices[ 1 ].set( min.x, max.y, max.z ); + vertices[ 2 ].set( min.x, min.y, max.z ); + vertices[ 3 ].set( max.x, min.y, max.z ); + vertices[ 4 ].set( max.x, max.y, min.z ); + vertices[ 5 ].set( min.x, max.y, min.z ); + vertices[ 6 ].set( min.x, min.y, min.z ); + vertices[ 7 ].set( max.x, min.y, min.z ); + + this.geometry.computeBoundingSphere(); + this.geometry.verticesNeedUpdate = true; + + this.matrixAutoUpdate = false; + this.matrixWorld = object.matrixWorld; + +}; + +/** + * @author WestLangley / http://github.com/WestLangley + */ + +// a helper to show the world-axis-aligned bounding box for an object + +THREE.BoundingBoxHelper = function ( object, hex ) { + + var color = ( hex !== undefined ) ? hex : 0x888888; + + this.object = object; + + this.box = new THREE.Box3(); + + THREE.Mesh.call( this, new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: color, wireframe: true } ) ); + +}; + +THREE.BoundingBoxHelper.prototype = Object.create( THREE.Mesh.prototype ); + +THREE.BoundingBoxHelper.prototype.update = function () { + + this.box.setFromObject( this.object ); + + this.box.size( this.scale ); + + this.box.center( this.position ); + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + * + * - shows frustum, line of sight and up of the camera + * - suitable for fast updates + * - based on frustum visualization in lightgl.js shadowmap example + * http://evanw.github.com/lightgl.js/tests/shadowmap.html + */ + +THREE.CameraHelper = function ( camera ) { + + var geometry = new THREE.Geometry(); + var material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } ); + + var pointMap = {}; + + // colors + + var hexFrustum = 0xffaa00; + var hexCone = 0xff0000; + var hexUp = 0x00aaff; + var hexTarget = 0xffffff; + var hexCross = 0x333333; + + // near + + addLine( "n1", "n2", hexFrustum ); + addLine( "n2", "n4", hexFrustum ); + addLine( "n4", "n3", hexFrustum ); + addLine( "n3", "n1", hexFrustum ); + + // far + + addLine( "f1", "f2", hexFrustum ); + addLine( "f2", "f4", hexFrustum ); + addLine( "f4", "f3", hexFrustum ); + addLine( "f3", "f1", hexFrustum ); + + // sides + + addLine( "n1", "f1", hexFrustum ); + addLine( "n2", "f2", hexFrustum ); + addLine( "n3", "f3", hexFrustum ); + addLine( "n4", "f4", hexFrustum ); + + // cone + + addLine( "p", "n1", hexCone ); + addLine( "p", "n2", hexCone ); + addLine( "p", "n3", hexCone ); + addLine( "p", "n4", hexCone ); + + // up + + addLine( "u1", "u2", hexUp ); + addLine( "u2", "u3", hexUp ); + addLine( "u3", "u1", hexUp ); + + // target + + addLine( "c", "t", hexTarget ); + addLine( "p", "c", hexCross ); + + // cross + + addLine( "cn1", "cn2", hexCross ); + addLine( "cn3", "cn4", hexCross ); + + addLine( "cf1", "cf2", hexCross ); + addLine( "cf3", "cf4", hexCross ); + + function addLine( a, b, hex ) { + + addPoint( a, hex ); + addPoint( b, hex ); + + } + + function addPoint( id, hex ) { + + geometry.vertices.push( new THREE.Vector3() ); + geometry.colors.push( new THREE.Color( hex ) ); + + if ( pointMap[ id ] === undefined ) { + + pointMap[ id ] = []; + + } + + pointMap[ id ].push( geometry.vertices.length - 1 ); + + } + + THREE.Line.call( this, geometry, material, THREE.LinePieces ); + + this.camera = camera; + this.matrixWorld = camera.matrixWorld; + this.matrixAutoUpdate = false; + + this.pointMap = pointMap; + + this.update(); + +}; + +THREE.CameraHelper.prototype = Object.create( THREE.Line.prototype ); + +THREE.CameraHelper.prototype.update = function () { + + var vector = new THREE.Vector3(); + var camera = new THREE.Camera(); + var projector = new THREE.Projector(); + + return function () { + + var scope = this; + + var w = 1, h = 1; + + // we need just camera projection matrix + // world matrix must be identity + + camera.projectionMatrix.copy( this.camera.projectionMatrix ); + + // center / target + + setPoint( "c", 0, 0, -1 ); + setPoint( "t", 0, 0, 1 ); + + // near + + setPoint( "n1", -w, -h, -1 ); + setPoint( "n2", w, -h, -1 ); + setPoint( "n3", -w, h, -1 ); + setPoint( "n4", w, h, -1 ); + + // far + + setPoint( "f1", -w, -h, 1 ); + setPoint( "f2", w, -h, 1 ); + setPoint( "f3", -w, h, 1 ); + setPoint( "f4", w, h, 1 ); + + // up + + setPoint( "u1", w * 0.7, h * 1.1, -1 ); + setPoint( "u2", -w * 0.7, h * 1.1, -1 ); + setPoint( "u3", 0, h * 2, -1 ); + + // cross + + setPoint( "cf1", -w, 0, 1 ); + setPoint( "cf2", w, 0, 1 ); + setPoint( "cf3", 0, -h, 1 ); + setPoint( "cf4", 0, h, 1 ); + + setPoint( "cn1", -w, 0, -1 ); + setPoint( "cn2", w, 0, -1 ); + setPoint( "cn3", 0, -h, -1 ); + setPoint( "cn4", 0, h, -1 ); + + function setPoint( point, x, y, z ) { + + vector.set( x, y, z ); + projector.unprojectVector( vector, camera ); + + var points = scope.pointMap[ point ]; + + if ( points !== undefined ) { + + for ( var i = 0, il = points.length; i < il; i ++ ) { + + scope.geometry.vertices[ points[ i ] ].copy( vector ); + + } + + } + + } + + this.geometry.verticesNeedUpdate = true; + + }; + +}(); + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley + */ + +THREE.DirectionalLightHelper = function ( light, size ) { + + THREE.Object3D.call( this ); + + this.light = light; + this.light.updateMatrixWorld(); + + this.matrixWorld = light.matrixWorld; + this.matrixAutoUpdate = false; + + size = size || 1; + var geometry = new THREE.PlaneGeometry( size, size ); + var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + this.lightPlane = new THREE.Mesh( geometry, material ); + this.add( this.lightPlane ); + + geometry = new THREE.Geometry(); + geometry.vertices.push( new THREE.Vector3() ); + geometry.vertices.push( new THREE.Vector3() ); + + material = new THREE.LineBasicMaterial( { fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + this.targetLine = new THREE.Line( geometry, material ); + this.add( this.targetLine ); + + this.update(); + +}; + +THREE.DirectionalLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.DirectionalLightHelper.prototype.dispose = function () { + + this.lightPlane.geometry.dispose(); + this.lightPlane.material.dispose(); + this.targetLine.geometry.dispose(); + this.targetLine.material.dispose(); +}; + +THREE.DirectionalLightHelper.prototype.update = function () { + + var v1 = new THREE.Vector3(); + var v2 = new THREE.Vector3(); + var v3 = new THREE.Vector3(); + + return function () { + + v1.setFromMatrixPosition( this.light.matrixWorld ); + v2.setFromMatrixPosition( this.light.target.matrixWorld ); + v3.subVectors( v2, v1 ); + + this.lightPlane.lookAt( v3 ); + this.lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + this.targetLine.geometry.vertices[ 1 ].copy( v3 ); + this.targetLine.geometry.verticesNeedUpdate = true; + this.targetLine.material.color.copy( this.lightPlane.material.color ); + + } + +}(); + + +/** + * @author WestLangley / http://github.com/WestLangley + */ + +THREE.EdgesHelper = function ( object, hex ) { + + var color = ( hex !== undefined ) ? hex : 0xffffff; + + var edge = [ 0, 0 ], hash = {}; + var sortFunction = function ( a, b ) { return a - b }; + + var keys = [ 'a', 'b', 'c' ]; + var geometry = new THREE.BufferGeometry(); + + var geometry2 = object.geometry.clone(); + + geometry2.mergeVertices(); + geometry2.computeFaceNormals(); + + var vertices = geometry2.vertices; + var faces = geometry2.faces; + var numEdges = 0; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + for ( var j = 0; j < 3; j ++ ) { + + edge[ 0 ] = face[ keys[ j ] ]; + edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; + edge.sort( sortFunction ); + + var key = edge.toString(); + + if ( hash[ key ] === undefined ) { + + hash[ key ] = { vert1: edge[ 0 ], vert2: edge[ 1 ], face1: i, face2: undefined }; + numEdges ++; + + } else { + + hash[ key ].face2 = i; + + } + + } + + } + + geometry.addAttribute( 'position', Float32Array, 2 * numEdges, 3 ); + + var coords = geometry.attributes.position.array; + + var index = 0; + + for ( var key in hash ) { + + var h = hash[ key ]; + + if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) < 0.9999 ) { // hardwired const OK + + var vertex = vertices[ h.vert1 ]; + coords[ index ++ ] = vertex.x; + coords[ index ++ ] = vertex.y; + coords[ index ++ ] = vertex.z; + + vertex = vertices[ h.vert2 ]; + coords[ index ++ ] = vertex.x; + coords[ index ++ ] = vertex.y; + coords[ index ++ ] = vertex.z; + + } + + } + + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); + + this.matrixAutoUpdate = false; + this.matrixWorld = object.matrixWorld; + +}; + +THREE.EdgesHelper.prototype = Object.create( THREE.Line.prototype ); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ + +THREE.FaceNormalsHelper = function ( object, size, hex, linewidth ) { + + this.object = object; + + this.size = ( size !== undefined ) ? size : 1; + + var color = ( hex !== undefined ) ? hex : 0xffff00; + + var width = ( linewidth !== undefined ) ? linewidth : 1; + + var geometry = new THREE.Geometry(); + + var faces = this.object.geometry.faces; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + geometry.vertices.push( new THREE.Vector3() ); + geometry.vertices.push( new THREE.Vector3() ); + + } + + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); + + this.matrixAutoUpdate = false; + + this.normalMatrix = new THREE.Matrix3(); + + this.update(); + +}; + +THREE.FaceNormalsHelper.prototype = Object.create( THREE.Line.prototype ); + +THREE.FaceNormalsHelper.prototype.update = ( function ( object ) { + + var v1 = new THREE.Vector3(); + + return function ( object ) { + + this.object.updateMatrixWorld( true ); + + this.normalMatrix.getNormalMatrix( this.object.matrixWorld ); + + var vertices = this.geometry.vertices; + + var faces = this.object.geometry.faces; + + var worldMatrix = this.object.matrixWorld; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + v1.copy( face.normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size ); + + var idx = 2 * i; + + vertices[ idx ].copy( face.centroid ).applyMatrix4( worldMatrix ); + + vertices[ idx + 1 ].addVectors( vertices[ idx ], v1 ); + + } + + this.geometry.verticesNeedUpdate = true; + + return this; + + } + +}()); + + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.GridHelper = function ( size, step ) { + + var geometry = new THREE.Geometry(); + var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); + + this.color1 = new THREE.Color( 0x444444 ); + this.color2 = new THREE.Color( 0x888888 ); + + for ( var i = - size; i <= size; i += step ) { + + geometry.vertices.push( + new THREE.Vector3( - size, 0, i ), new THREE.Vector3( size, 0, i ), + new THREE.Vector3( i, 0, - size ), new THREE.Vector3( i, 0, size ) + ); + + var color = i === 0 ? this.color1 : this.color2; + + geometry.colors.push( color, color, color, color ); + + } + + THREE.Line.call( this, geometry, material, THREE.LinePieces ); + +}; + +THREE.GridHelper.prototype = Object.create( THREE.Line.prototype ); + +THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) { + + this.color1.set( colorCenterLine ); + this.color2.set( colorGrid ); + + this.geometry.colorsNeedUpdate = true; + +} + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.HemisphereLightHelper = function ( light, sphereSize, arrowLength, domeSize ) { + + THREE.Object3D.call( this ); + + this.light = light; + this.light.updateMatrixWorld(); + + this.matrixWorld = light.matrixWorld; + this.matrixAutoUpdate = false; + + this.colors = [ new THREE.Color(), new THREE.Color() ]; + + var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); + geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); + + for ( var i = 0, il = 8; i < il; i ++ ) { + + geometry.faces[ i ].color = this.colors[ i < 4 ? 0 : 1 ]; + + } + + var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: true } ); + + this.lightSphere = new THREE.Mesh( geometry, material ); + this.add( this.lightSphere ); + + this.update(); + +}; + +THREE.HemisphereLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.HemisphereLightHelper.prototype.dispose = function () { + this.lightSphere.geometry.dispose(); + this.lightSphere.material.dispose(); +}; + +THREE.HemisphereLightHelper.prototype.update = function () { + + var vector = new THREE.Vector3(); + + return function () { + + this.colors[ 0 ].copy( this.light.color ).multiplyScalar( this.light.intensity ); + this.colors[ 1 ].copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); + + this.lightSphere.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); + this.lightSphere.geometry.colorsNeedUpdate = true; + + } + +}(); + + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.PointLightHelper = function ( light, sphereSize ) { + + this.light = light; + this.light.updateMatrixWorld(); + + var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); + var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); + material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + THREE.Mesh.call( this, geometry, material ); + + this.matrixWorld = this.light.matrixWorld; + this.matrixAutoUpdate = false; + + /* + var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); + var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); + + this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); + this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); + + var d = light.distance; + + if ( d === 0.0 ) { + + this.lightDistance.visible = false; + + } else { + + this.lightDistance.scale.set( d, d, d ); + + } + + this.add( this.lightDistance ); + */ + +}; + +THREE.PointLightHelper.prototype = Object.create( THREE.Mesh.prototype ); + +THREE.PointLightHelper.prototype.dispose = function () { + + this.geometry.dispose(); + this.material.dispose(); +}; + +THREE.PointLightHelper.prototype.update = function () { + + this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + /* + var d = this.light.distance; + + if ( d === 0.0 ) { + + this.lightDistance.visible = false; + + } else { + + this.lightDistance.visible = true; + this.lightDistance.scale.set( d, d, d ); + + } + */ + +}; + + +/** + * @author alteredq / http://alteredqualia.com/ + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ + +THREE.SpotLightHelper = function ( light ) { + + THREE.Object3D.call( this ); + + this.light = light; + this.light.updateMatrixWorld(); + + this.matrixWorld = light.matrixWorld; + this.matrixAutoUpdate = false; + + var geometry = new THREE.CylinderGeometry( 0, 1, 1, 8, 1, true ); + + geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, -0.5, 0 ) ); + geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); + + var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); + + this.cone = new THREE.Mesh( geometry, material ); + this.add( this.cone ); + + this.update(); + +}; + +THREE.SpotLightHelper.prototype = Object.create( THREE.Object3D.prototype ); + +THREE.SpotLightHelper.prototype.dispose = function () { + this.cone.geometry.dispose(); + this.cone.material.dispose(); +}; + +THREE.SpotLightHelper.prototype.update = function () { + + var vector = new THREE.Vector3(); + var vector2 = new THREE.Vector3(); + + return function () { + + var coneLength = this.light.distance ? this.light.distance : 10000; + var coneWidth = coneLength * Math.tan( this.light.angle ); + + this.cone.scale.set( coneWidth, coneWidth, coneLength ); + + vector.setFromMatrixPosition( this.light.matrixWorld ); + vector2.setFromMatrixPosition( this.light.target.matrixWorld ); + + this.cone.lookAt( vector2.sub( vector ) ); + + this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); + + }; + +}(); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ + +THREE.VertexNormalsHelper = function ( object, size, hex, linewidth ) { + + this.object = object; + + this.size = ( size !== undefined ) ? size : 1; + + var color = ( hex !== undefined ) ? hex : 0xff0000; + + var width = ( linewidth !== undefined ) ? linewidth : 1; + + var geometry = new THREE.Geometry(); + + var vertices = object.geometry.vertices; + + var faces = object.geometry.faces; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + + geometry.vertices.push( new THREE.Vector3() ); + geometry.vertices.push( new THREE.Vector3() ); + + } + + } + + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); + + this.matrixAutoUpdate = false; + + this.normalMatrix = new THREE.Matrix3(); + + this.update(); + +}; + +THREE.VertexNormalsHelper.prototype = Object.create( THREE.Line.prototype ); + +THREE.VertexNormalsHelper.prototype.update = ( function ( object ) { + + var v1 = new THREE.Vector3(); + + return function( object ) { + + var keys = [ 'a', 'b', 'c', 'd' ]; + + this.object.updateMatrixWorld( true ); + + this.normalMatrix.getNormalMatrix( this.object.matrixWorld ); + + var vertices = this.geometry.vertices; + + var verts = this.object.geometry.vertices; + + var faces = this.object.geometry.faces; + + var worldMatrix = this.object.matrixWorld; + + var idx = 0; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + + var vertexId = face[ keys[ j ] ]; + var vertex = verts[ vertexId ]; + + var normal = face.vertexNormals[ j ]; + + vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); + + v1.copy( normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size ); + + v1.add( vertices[ idx ] ); + idx = idx + 1; + + vertices[ idx ].copy( v1 ); + idx = idx + 1; + + } + + } + + this.geometry.verticesNeedUpdate = true; + + return this; + + } + +}()); + +/** + * @author mrdoob / http://mrdoob.com/ + * @author WestLangley / http://github.com/WestLangley +*/ + +THREE.VertexTangentsHelper = function ( object, size, hex, linewidth ) { + + this.object = object; + + this.size = ( size !== undefined ) ? size : 1; + + var color = ( hex !== undefined ) ? hex : 0x0000ff; + + var width = ( linewidth !== undefined ) ? linewidth : 1; + + var geometry = new THREE.Geometry(); + + var vertices = object.geometry.vertices; + + var faces = object.geometry.faces; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { + + geometry.vertices.push( new THREE.Vector3() ); + geometry.vertices.push( new THREE.Vector3() ); + + } + + } + + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); + + this.matrixAutoUpdate = false; + + this.update(); + +}; + +THREE.VertexTangentsHelper.prototype = Object.create( THREE.Line.prototype ); + +THREE.VertexTangentsHelper.prototype.update = ( function ( object ) { + + var v1 = new THREE.Vector3(); + + return function( object ) { + + var keys = [ 'a', 'b', 'c', 'd' ]; + + this.object.updateMatrixWorld( true ); + + var vertices = this.geometry.vertices; + + var verts = this.object.geometry.vertices; + + var faces = this.object.geometry.faces; + + var worldMatrix = this.object.matrixWorld; + + var idx = 0; + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { + + var vertexId = face[ keys[ j ] ]; + var vertex = verts[ vertexId ]; + + var tangent = face.vertexTangents[ j ]; + + vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); + + v1.copy( tangent ).transformDirection( worldMatrix ).multiplyScalar( this.size ); + + v1.add( vertices[ idx ] ); + idx = idx + 1; + + vertices[ idx ].copy( v1 ); + idx = idx + 1; + + } + + } + + this.geometry.verticesNeedUpdate = true; + + return this; + + } + +}()); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.WireframeHelper = function ( object, hex ) { + + var color = ( hex !== undefined ) ? hex : 0xffffff; + + var edge = [ 0, 0 ], hash = {}; + var sortFunction = function ( a, b ) { return a - b }; + + var keys = [ 'a', 'b', 'c' ]; + var geometry = new THREE.BufferGeometry(); + + if ( object.geometry instanceof THREE.Geometry ) { + + var vertices = object.geometry.vertices; + var faces = object.geometry.faces; + var numEdges = 0; + + // allocate maximal size + var edges = new Uint32Array( 6 * faces.length ); + + for ( var i = 0, l = faces.length; i < l; i ++ ) { + + var face = faces[ i ]; + + for ( var j = 0; j < 3; j ++ ) { + + edge[ 0 ] = face[ keys[ j ] ]; + edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; + edge.sort( sortFunction ); + + var key = edge.toString(); + + if ( hash[ key ] === undefined ) { + + edges[ 2 * numEdges ] = edge[ 0 ]; + edges[ 2 * numEdges + 1 ] = edge[ 1 ]; + hash[ key ] = true; + numEdges ++; + + } + + } + + } + + geometry.addAttribute( 'position', Float32Array, 2 * numEdges, 3 ); + + var coords = geometry.attributes.position.array; + + for ( var i = 0, l = numEdges; i < l; i ++ ) { + + for ( var j = 0; j < 2; j ++ ) { + + var vertex = vertices[ edges [ 2 * i + j] ]; + + var index = 6 * i + 3 * j; + coords[ index + 0 ] = vertex.x; + coords[ index + 1 ] = vertex.y; + coords[ index + 2 ] = vertex.z; + + } + + } + + } else if ( object.geometry instanceof THREE.BufferGeometry && object.geometry.attributes.index !== undefined ) { // indexed BufferGeometry + + var vertices = object.geometry.attributes.position.array; + var indices = object.geometry.attributes.index.array; + var offsets = object.geometry.offsets; + var numEdges = 0; + + // allocate maximal size + var edges = new Uint32Array( 2 * indices.length ); + + for ( var o = 0, ol = offsets.length; o < ol; ++ o ) { + + var start = offsets[ o ].start; + var count = offsets[ o ].count; + var index = offsets[ o ].index; + + for ( var i = start, il = start + count; i < il; i += 3 ) { + + for ( var j = 0; j < 3; j ++ ) { + + edge[ 0 ] = index + indices[ i + j ]; + edge[ 1 ] = index + indices[ i + ( j + 1 ) % 3 ]; + edge.sort( sortFunction ); + + var key = edge.toString(); + + if ( hash[ key ] === undefined ) { + + edges[ 2 * numEdges ] = edge[ 0 ]; + edges[ 2 * numEdges + 1 ] = edge[ 1 ]; + hash[ key ] = true; + numEdges ++; + + } + + } + + } + + } + + geometry.addAttribute( 'position', Float32Array, 2 * numEdges, 3 ); + + var coords = geometry.attributes.position.array; + + for ( var i = 0, l = numEdges; i < l; i ++ ) { + + for ( var j = 0; j < 2; j ++ ) { + + var index = 6 * i + 3 * j; + var index2 = 3 * edges[ 2 * i + j]; + coords[ index + 0 ] = vertices[ index2 ]; + coords[ index + 1 ] = vertices[ index2 + 1 ]; + coords[ index + 2 ] = vertices[ index2 + 2 ]; + + } + + } + + } else if ( object.geometry instanceof THREE.BufferGeometry ) { // non-indexed BufferGeometry + + var vertices = object.geometry.attributes.position.array; + var numEdges = vertices.length / 3; + var numTris = numEdges / 3; + + geometry.addAttribute( 'position', Float32Array, 2 * numEdges, 3 ); + + var coords = geometry.attributes.position.array; + + for ( var i = 0, l = numTris; i < l; i ++ ) { + + for ( var j = 0; j < 3; j ++ ) { + + var index = 18 * i + 6 * j; + + var index1 = 9 * i + 3 * j; + coords[ index + 0 ] = vertices[ index1 ]; + coords[ index + 1 ] = vertices[ index1 + 1 ]; + coords[ index + 2 ] = vertices[ index1 + 2 ]; + + var index2 = 9 * i + 3 * ( ( j + 1 ) % 3 ); + coords[ index + 3 ] = vertices[ index2 ]; + coords[ index + 4 ] = vertices[ index2 + 1 ]; + coords[ index + 5 ] = vertices[ index2 + 2 ]; + + } + + } + + } + + THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); + + this.matrixAutoUpdate = false; + this.matrixWorld = object.matrixWorld; + +}; + +THREE.WireframeHelper.prototype = Object.create( THREE.Line.prototype ); + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.ImmediateRenderObject = function () { + + THREE.Object3D.call( this ); + + this.render = function ( renderCallback ) { }; + +}; + +THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype ); + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.LensFlare = function ( texture, size, distance, blending, color ) { + + THREE.Object3D.call( this ); + + this.lensFlares = []; + + this.positionScreen = new THREE.Vector3(); + this.customUpdateCallback = undefined; + + if( texture !== undefined ) { + + this.add( texture, size, distance, blending, color ); + + } + +}; + +THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype ); + + +/* + * Add: adds another flare + */ + +THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) { + + if( size === undefined ) size = -1; + if( distance === undefined ) distance = 0; + if( opacity === undefined ) opacity = 1; + if( color === undefined ) color = new THREE.Color( 0xffffff ); + if( blending === undefined ) blending = THREE.NormalBlending; + + distance = Math.min( distance, Math.max( 0, distance ) ); + + this.lensFlares.push( { texture: texture, // THREE.Texture + size: size, // size in pixels (-1 = use texture.width) + distance: distance, // distance (0-1) from light source (0=at light source) + x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is ontop z = 1 is back + scale: 1, // scale + rotation: 1, // rotation + opacity: opacity, // opacity + color: color, // color + blending: blending } ); // blending + +}; + + +/* + * Update lens flares update positions on all flares based on the screen position + * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way. + */ + +THREE.LensFlare.prototype.updateLensFlares = function () { + + var f, fl = this.lensFlares.length; + var flare; + var vecX = -this.positionScreen.x * 2; + var vecY = -this.positionScreen.y * 2; + + for( f = 0; f < fl; f ++ ) { + + flare = this.lensFlares[ f ]; + + flare.x = this.positionScreen.x + vecX * flare.distance; + flare.y = this.positionScreen.y + vecY * flare.distance; + + flare.wantedRotation = flare.x * Math.PI * 0.25; + flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; + + } + +}; + + + + + + + + + + + + + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.MorphBlendMesh = function( geometry, material ) { + + THREE.Mesh.call( this, geometry, material ); + + this.animationsMap = {}; + this.animationsList = []; + + // prepare default animation + // (all frames played together in 1 second) + + var numFrames = this.geometry.morphTargets.length; + + var name = "__default"; + + var startFrame = 0; + var endFrame = numFrames - 1; + + var fps = numFrames / 1; + + this.createAnimation( name, startFrame, endFrame, fps ); + this.setAnimationWeight( name, 1 ); + +}; + +THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype ); + +THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { + + var animation = { + + startFrame: start, + endFrame: end, + + length: end - start + 1, + + fps: fps, + duration: ( end - start ) / fps, + + lastFrame: 0, + currentFrame: 0, + + active: false, + + time: 0, + direction: 1, + weight: 1, + + directionBackwards: false, + mirroredLoop: false + + }; + + this.animationsMap[ name ] = animation; + this.animationsList.push( animation ); + +}; + +THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { + + var pattern = /([a-z]+)(\d+)/; + + var firstAnimation, frameRanges = {}; + + var geometry = this.geometry; + + for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { + + var morph = geometry.morphTargets[ i ]; + var chunks = morph.name.match( pattern ); + + if ( chunks && chunks.length > 1 ) { + + var name = chunks[ 1 ]; + var num = chunks[ 2 ]; + + if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: -Infinity }; + + var range = frameRanges[ name ]; + + if ( i < range.start ) range.start = i; + if ( i > range.end ) range.end = i; + + if ( ! firstAnimation ) firstAnimation = name; + + } + + } + + for ( var name in frameRanges ) { + + var range = frameRanges[ name ]; + this.createAnimation( name, range.start, range.end, fps ); + + } + + this.firstAnimation = firstAnimation; + +}; + +THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.direction = 1; + animation.directionBackwards = false; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.direction = -1; + animation.directionBackwards = true; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.fps = fps; + animation.duration = ( animation.end - animation.start ) / animation.fps; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.duration = duration; + animation.fps = ( animation.end - animation.start ) / animation.duration; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.weight = weight; + + } + +}; + +THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.time = time; + + } + +}; + +THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) { + + var time = 0; + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + time = animation.time; + + } + + return time; + +}; + +THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { + + var duration = -1; + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + duration = animation.duration; + + } + + return duration; + +}; + +THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.time = 0; + animation.active = true; + + } else { + + THREE.onwarning( "animation[" + name + "] undefined" ); + + } + +}; + +THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) { + + var animation = this.animationsMap[ name ]; + + if ( animation ) { + + animation.active = false; + + } + +}; + +THREE.MorphBlendMesh.prototype.update = function ( delta ) { + + for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) { + + var animation = this.animationsList[ i ]; + + if ( ! animation.active ) continue; + + var frameTime = animation.duration / animation.length; + + animation.time += animation.direction * delta; + + if ( animation.mirroredLoop ) { + + if ( animation.time > animation.duration || animation.time < 0 ) { + + animation.direction *= -1; + + if ( animation.time > animation.duration ) { + + animation.time = animation.duration; + animation.directionBackwards = true; + + } + + if ( animation.time < 0 ) { + + animation.time = 0; + animation.directionBackwards = false; + + } + + } + + } else { + + animation.time = animation.time % animation.duration; + + if ( animation.time < 0 ) animation.time += animation.duration; + + } + + var keyframe = animation.startFrame + THREE.Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 ); + var weight = animation.weight; + + if ( keyframe !== animation.currentFrame ) { + + this.morphTargetInfluences[ animation.lastFrame ] = 0; + this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight; + + this.morphTargetInfluences[ keyframe ] = 0; + + animation.lastFrame = animation.currentFrame; + animation.currentFrame = keyframe; + + } + + var mix = ( animation.time % frameTime ) / frameTime; + + if ( animation.directionBackwards ) mix = 1 - mix; + + this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; + this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; + + } + +}; + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.LensFlarePlugin = function () { + + var _gl, _renderer, _precision, _lensFlare = {}; + + this.init = function ( renderer ) { + + _gl = renderer.context; + _renderer = renderer; + + _precision = renderer.getPrecision(); + + _lensFlare.vertices = new Float32Array( 8 + 8 ); + _lensFlare.faces = new Uint16Array( 6 ); + + var i = 0; + _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = -1; // vertex + _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 0; // uv... etc. + + _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = -1; + _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 0; + + _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; + _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; + + _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = 1; + _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 1; + + i = 0; + _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 1; _lensFlare.faces[ i++ ] = 2; + _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 2; _lensFlare.faces[ i++ ] = 3; + + // buffers + + _lensFlare.vertexBuffer = _gl.createBuffer(); + _lensFlare.elementBuffer = _gl.createBuffer(); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, _lensFlare.vertices, _gl.STATIC_DRAW ); + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.faces, _gl.STATIC_DRAW ); + + // textures + + _lensFlare.tempTexture = _gl.createTexture(); + _lensFlare.occlusionTexture = _gl.createTexture(); + + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); + _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, 16, 16, 0, _gl.RGB, _gl.UNSIGNED_BYTE, null ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST ); + + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture ); + _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, 16, 16, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, null ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST ); + _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST ); + + if ( _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) <= 0 ) { + + _lensFlare.hasVertexTexture = false; + _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlare" ], _precision ); + + } else { + + _lensFlare.hasVertexTexture = true; + _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlareVertexTexture" ], _precision ); + + } + + _lensFlare.attributes = {}; + _lensFlare.uniforms = {}; + + _lensFlare.attributes.vertex = _gl.getAttribLocation ( _lensFlare.program, "position" ); + _lensFlare.attributes.uv = _gl.getAttribLocation ( _lensFlare.program, "uv" ); + + _lensFlare.uniforms.renderType = _gl.getUniformLocation( _lensFlare.program, "renderType" ); + _lensFlare.uniforms.map = _gl.getUniformLocation( _lensFlare.program, "map" ); + _lensFlare.uniforms.occlusionMap = _gl.getUniformLocation( _lensFlare.program, "occlusionMap" ); + _lensFlare.uniforms.opacity = _gl.getUniformLocation( _lensFlare.program, "opacity" ); + _lensFlare.uniforms.color = _gl.getUniformLocation( _lensFlare.program, "color" ); + _lensFlare.uniforms.scale = _gl.getUniformLocation( _lensFlare.program, "scale" ); + _lensFlare.uniforms.rotation = _gl.getUniformLocation( _lensFlare.program, "rotation" ); + _lensFlare.uniforms.screenPosition = _gl.getUniformLocation( _lensFlare.program, "screenPosition" ); + + }; + + + /* + * Render lens flares + * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, + * reads these back and calculates occlusion. + * Then _lensFlare.update_lensFlares() is called to re-position and + * update transparency of flares. Then they are rendered. + * + */ + + this.render = function ( scene, camera, viewportWidth, viewportHeight ) { + + var flares = scene.__webglFlares, + nFlares = flares.length; + + if ( ! nFlares ) return; + + var tempPosition = new THREE.Vector3(); + + var invAspect = viewportHeight / viewportWidth, + halfViewportWidth = viewportWidth * 0.5, + halfViewportHeight = viewportHeight * 0.5; + + var size = 16 / viewportHeight, + scale = new THREE.Vector2( size * invAspect, size ); + + var screenPosition = new THREE.Vector3( 1, 1, 0 ), + screenPositionPixels = new THREE.Vector2( 1, 1 ); + + var uniforms = _lensFlare.uniforms, + attributes = _lensFlare.attributes; + + // set _lensFlare program and reset blending + + _gl.useProgram( _lensFlare.program ); + + _gl.enableVertexAttribArray( _lensFlare.attributes.vertex ); + _gl.enableVertexAttribArray( _lensFlare.attributes.uv ); + + // loop through all lens flares to update their occlusion and positions + // setup gl and common used attribs/unforms + + _gl.uniform1i( uniforms.occlusionMap, 0 ); + _gl.uniform1i( uniforms.map, 1 ); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer ); + _gl.vertexAttribPointer( attributes.vertex, 2, _gl.FLOAT, false, 2 * 8, 0 ); + _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 ); + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer ); + + _gl.disable( _gl.CULL_FACE ); + _gl.depthMask( false ); + + var i, j, jl, flare, sprite; + + for ( i = 0; i < nFlares; i ++ ) { + + size = 16 / viewportHeight; + scale.set( size * invAspect, size ); + + // calc object screen position + + flare = flares[ i ]; + + tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] ); + + tempPosition.applyMatrix4( camera.matrixWorldInverse ); + tempPosition.applyProjection( camera.projectionMatrix ); + + // setup arrays for gl programs + + screenPosition.copy( tempPosition ) + + screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth; + screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight; + + // screen cull + + if ( _lensFlare.hasVertexTexture || ( + screenPositionPixels.x > 0 && + screenPositionPixels.x < viewportWidth && + screenPositionPixels.y > 0 && + screenPositionPixels.y < viewportHeight ) ) { + + // save current RGB to temp texture + + _gl.activeTexture( _gl.TEXTURE1 ); + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); + _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); + + + // render pink quad + + _gl.uniform1i( uniforms.renderType, 0 ); + _gl.uniform2f( uniforms.scale, scale.x, scale.y ); + _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); + + _gl.disable( _gl.BLEND ); + _gl.enable( _gl.DEPTH_TEST ); + + _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + + + // copy result to occlusionMap + + _gl.activeTexture( _gl.TEXTURE0 ); + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture ); + _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); + + + // restore graphics + + _gl.uniform1i( uniforms.renderType, 1 ); + _gl.disable( _gl.DEPTH_TEST ); + + _gl.activeTexture( _gl.TEXTURE1 ); + _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); + _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + + + // update object positions + + flare.positionScreen.copy( screenPosition ) + + if ( flare.customUpdateCallback ) { + + flare.customUpdateCallback( flare ); + + } else { + + flare.updateLensFlares(); + + } + + // render flares + + _gl.uniform1i( uniforms.renderType, 2 ); + _gl.enable( _gl.BLEND ); + + for ( j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { + + sprite = flare.lensFlares[ j ]; + + if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { + + screenPosition.x = sprite.x; + screenPosition.y = sprite.y; + screenPosition.z = sprite.z; + + size = sprite.size * sprite.scale / viewportHeight; + + scale.x = size * invAspect; + scale.y = size; + + _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); + _gl.uniform2f( uniforms.scale, scale.x, scale.y ); + _gl.uniform1f( uniforms.rotation, sprite.rotation ); + + _gl.uniform1f( uniforms.opacity, sprite.opacity ); + _gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b ); + + _renderer.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); + _renderer.setTexture( sprite.texture, 1 ); + + _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + + } + + } + + } + + } + + // restore gl + + _gl.enable( _gl.CULL_FACE ); + _gl.enable( _gl.DEPTH_TEST ); + _gl.depthMask( true ); + + }; + + function createProgram ( shader, precision ) { + + var program = _gl.createProgram(); + + var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER ); + var vertexShader = _gl.createShader( _gl.VERTEX_SHADER ); + + var prefix = "precision " + precision + " float;\n"; + + _gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); + _gl.shaderSource( vertexShader, prefix + shader.vertexShader ); + + _gl.compileShader( fragmentShader ); + _gl.compileShader( vertexShader ); + + _gl.attachShader( program, fragmentShader ); + _gl.attachShader( program, vertexShader ); + + _gl.linkProgram( program ); + + return program; + + }; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.ShadowMapPlugin = function () { + + var _gl, + _renderer, + _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, + + _frustum = new THREE.Frustum(), + _projScreenMatrix = new THREE.Matrix4(), + + _min = new THREE.Vector3(), + _max = new THREE.Vector3(), + + _matrixPosition = new THREE.Vector3(); + + this.init = function ( renderer ) { + + _gl = renderer.context; + _renderer = renderer; + + var depthShader = THREE.ShaderLib[ "depthRGBA" ]; + var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); + + _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); + _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); + _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); + _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); + + _depthMaterial._shadowPass = true; + _depthMaterialMorph._shadowPass = true; + _depthMaterialSkin._shadowPass = true; + _depthMaterialMorphSkin._shadowPass = true; + + }; + + this.render = function ( scene, camera ) { + + if ( ! ( _renderer.shadowMapEnabled && _renderer.shadowMapAutoUpdate ) ) return; + + this.update( scene, camera ); + + }; + + this.update = function ( scene, camera ) { + + var i, il, j, jl, n, + + shadowMap, shadowMatrix, shadowCamera, + program, buffer, material, + webglObject, object, light, + renderList, + + lights = [], + k = 0, + + fog = null; + + // set GL state for depth map + + _gl.clearColor( 1, 1, 1, 1 ); + _gl.disable( _gl.BLEND ); + + _gl.enable( _gl.CULL_FACE ); + _gl.frontFace( _gl.CCW ); + + if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { + + _gl.cullFace( _gl.FRONT ); + + } else { + + _gl.cullFace( _gl.BACK ); + + } + + _renderer.setDepthTest( true ); + + // preprocess lights + // - skip lights that are not casting shadows + // - create virtual lights for cascaded shadow maps + + for ( i = 0, il = scene.__lights.length; i < il; i ++ ) { + + light = scene.__lights[ i ]; + + if ( ! light.castShadow ) continue; + + if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) { + + for ( n = 0; n < light.shadowCascadeCount; n ++ ) { + + var virtualLight; + + if ( ! light.shadowCascadeArray[ n ] ) { + + virtualLight = createVirtualLight( light, n ); + virtualLight.originalCamera = camera; + + var gyro = new THREE.Gyroscope(); + gyro.position = light.shadowCascadeOffset; + + gyro.add( virtualLight ); + gyro.add( virtualLight.target ); + + camera.add( gyro ); + + light.shadowCascadeArray[ n ] = virtualLight; + + //console.log( "Created virtualLight", virtualLight ); + + } else { + + virtualLight = light.shadowCascadeArray[ n ]; + + } + + updateVirtualLight( light, n ); + + lights[ k ] = virtualLight; + k ++; + + } + + } else { + + lights[ k ] = light; + k ++; + + } + + } + + // render depth map + + for ( i = 0, il = lights.length; i < il; i ++ ) { + + light = lights[ i ]; + + if ( ! light.shadowMap ) { + + var shadowFilter = THREE.NearestFilter; + + if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) { + + shadowFilter = THREE.NearestFilter; + + } + + var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat }; + + light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars ); + light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight ); + + light.shadowMatrix = new THREE.Matrix4(); + + } + + if ( ! light.shadowCamera ) { + + if ( light instanceof THREE.SpotLight ) { + + light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar ); + + } else if ( light instanceof THREE.DirectionalLight ) { + + light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar ); + + } else { + + THREE.onerror( "Unsupported light type for shadow" ); + continue; + + } + + scene.add( light.shadowCamera ); + + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + + } + + if ( light.shadowCameraVisible && ! light.cameraHelper ) { + + light.cameraHelper = new THREE.CameraHelper( light.shadowCamera ); + light.shadowCamera.add( light.cameraHelper ); + + } + + if ( light.isVirtual && virtualLight.originalCamera == camera ) { + + updateShadowCamera( camera, light ); + + } + + shadowMap = light.shadowMap; + shadowMatrix = light.shadowMatrix; + shadowCamera = light.shadowCamera; + + shadowCamera.position.setFromMatrixPosition( light.matrixWorld ); + _matrixPosition.setFromMatrixPosition( light.target.matrixWorld ); + shadowCamera.lookAt( _matrixPosition ); + shadowCamera.updateMatrixWorld(); + + shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); + + if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible; + if ( light.shadowCameraVisible ) light.cameraHelper.update(); + + // compute shadow matrix + + shadowMatrix.set( 0.5, 0.0, 0.0, 0.5, + 0.0, 0.5, 0.0, 0.5, + 0.0, 0.0, 0.5, 0.5, + 0.0, 0.0, 0.0, 1.0 ); + + shadowMatrix.multiply( shadowCamera.projectionMatrix ); + shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); + + // update camera matrices and frustum + + _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); + + // render shadow map + + _renderer.setRenderTarget( shadowMap ); + _renderer.clear(); + + // set object matrices & frustum culling + + renderList = scene.__webglObjects; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + object = webglObject.object; + + webglObject.render = false; + + if ( object.visible && object.castShadow ) { + + if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { + + object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + + webglObject.render = true; + + } + + } + + } + + // render regular objects + + var objectMaterial, useMorphing, useSkinning; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + + if ( webglObject.render ) { + + object = webglObject.object; + buffer = webglObject.buffer; + + // culling is overriden globally for all objects + // while rendering depth map + + // need to deal with MeshFaceMaterial somehow + // in that case just use the first of material.materials for now + // (proper solution would require to break objects by materials + // similarly to regular rendering and then set corresponding + // depth materials per each chunk instead of just once per object) + + objectMaterial = getObjectMaterial( object ); + + useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; + useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; + + if ( object.customDepthMaterial ) { + + material = object.customDepthMaterial; + + } else if ( useSkinning ) { + + material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; + + } else if ( useMorphing ) { + + material = _depthMaterialMorph; + + } else { + + material = _depthMaterial; + + } + + if ( buffer instanceof THREE.BufferGeometry ) { + + _renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object ); + + } else { + + _renderer.renderBuffer( shadowCamera, scene.__lights, fog, material, buffer, object ); + + } + + } + + } + + // set matrices and render immediate objects + + renderList = scene.__webglObjectsImmediate; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + object = webglObject.object; + + if ( object.visible && object.castShadow ) { + + object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + + _renderer.renderImmediateObject( shadowCamera, scene.__lights, fog, _depthMaterial, object ); + + } + + } + + } + + // restore GL state + + var clearColor = _renderer.getClearColor(), + clearAlpha = _renderer.getClearAlpha(); + + _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); + _gl.enable( _gl.BLEND ); + + if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { + + _gl.cullFace( _gl.BACK ); + + } + + }; + + function createVirtualLight( light, cascade ) { + + var virtualLight = new THREE.DirectionalLight(); + + virtualLight.isVirtual = true; + + virtualLight.onlyShadow = true; + virtualLight.castShadow = true; + + virtualLight.shadowCameraNear = light.shadowCameraNear; + virtualLight.shadowCameraFar = light.shadowCameraFar; + + virtualLight.shadowCameraLeft = light.shadowCameraLeft; + virtualLight.shadowCameraRight = light.shadowCameraRight; + virtualLight.shadowCameraBottom = light.shadowCameraBottom; + virtualLight.shadowCameraTop = light.shadowCameraTop; + + virtualLight.shadowCameraVisible = light.shadowCameraVisible; + + virtualLight.shadowDarkness = light.shadowDarkness; + + virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; + virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ]; + virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ]; + + virtualLight.pointsWorld = []; + virtualLight.pointsFrustum = []; + + var pointsWorld = virtualLight.pointsWorld, + pointsFrustum = virtualLight.pointsFrustum; + + for ( var i = 0; i < 8; i ++ ) { + + pointsWorld[ i ] = new THREE.Vector3(); + pointsFrustum[ i ] = new THREE.Vector3(); + + } + + var nearZ = light.shadowCascadeNearZ[ cascade ]; + var farZ = light.shadowCascadeFarZ[ cascade ]; + + pointsFrustum[ 0 ].set( -1, -1, nearZ ); + pointsFrustum[ 1 ].set( 1, -1, nearZ ); + pointsFrustum[ 2 ].set( -1, 1, nearZ ); + pointsFrustum[ 3 ].set( 1, 1, nearZ ); + + pointsFrustum[ 4 ].set( -1, -1, farZ ); + pointsFrustum[ 5 ].set( 1, -1, farZ ); + pointsFrustum[ 6 ].set( -1, 1, farZ ); + pointsFrustum[ 7 ].set( 1, 1, farZ ); + + return virtualLight; + + } + + // Synchronize virtual light with the original light + + function updateVirtualLight( light, cascade ) { + + var virtualLight = light.shadowCascadeArray[ cascade ]; + + virtualLight.position.copy( light.position ); + virtualLight.target.position.copy( light.target.position ); + virtualLight.lookAt( virtualLight.target ); + + virtualLight.shadowCameraVisible = light.shadowCameraVisible; + virtualLight.shadowDarkness = light.shadowDarkness; + + virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; + + var nearZ = light.shadowCascadeNearZ[ cascade ]; + var farZ = light.shadowCascadeFarZ[ cascade ]; + + var pointsFrustum = virtualLight.pointsFrustum; + + pointsFrustum[ 0 ].z = nearZ; + pointsFrustum[ 1 ].z = nearZ; + pointsFrustum[ 2 ].z = nearZ; + pointsFrustum[ 3 ].z = nearZ; + + pointsFrustum[ 4 ].z = farZ; + pointsFrustum[ 5 ].z = farZ; + pointsFrustum[ 6 ].z = farZ; + pointsFrustum[ 7 ].z = farZ; + + } + + // Fit shadow camera's ortho frustum to camera frustum + + function updateShadowCamera( camera, light ) { + + var shadowCamera = light.shadowCamera, + pointsFrustum = light.pointsFrustum, + pointsWorld = light.pointsWorld; + + _min.set( Infinity, Infinity, Infinity ); + _max.set( -Infinity, -Infinity, -Infinity ); + + for ( var i = 0; i < 8; i ++ ) { + + var p = pointsWorld[ i ]; + + p.copy( pointsFrustum[ i ] ); + THREE.ShadowMapPlugin.__projector.unprojectVector( p, camera ); + + p.applyMatrix4( shadowCamera.matrixWorldInverse ); + + if ( p.x < _min.x ) _min.x = p.x; + if ( p.x > _max.x ) _max.x = p.x; + + if ( p.y < _min.y ) _min.y = p.y; + if ( p.y > _max.y ) _max.y = p.y; + + if ( p.z < _min.z ) _min.z = p.z; + if ( p.z > _max.z ) _max.z = p.z; + + } + + shadowCamera.left = _min.x; + shadowCamera.right = _max.x; + shadowCamera.top = _max.y; + shadowCamera.bottom = _min.y; + + // can't really fit near/far + //shadowCamera.near = _min.z; + //shadowCamera.far = _max.z; + + shadowCamera.updateProjectionMatrix(); + + } + + // For the moment just ignore objects that have multiple materials with different animation methods + // Only the first material will be taken into account for deciding which depth material to use for shadow maps + + function getObjectMaterial( object ) { + + return object.material instanceof THREE.MeshFaceMaterial + ? object.material.materials[ 0 ] + : object.material; + + }; + +}; + +THREE.ShadowMapPlugin.__projector = new THREE.Projector(); + +/** + * @author mikael emtinger / http://gomo.se/ + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.SpritePlugin = function () { + + var _gl, _renderer, _texture; + + var vertices, faces, vertexBuffer, elementBuffer; + var program, attributes, uniforms; + + this.init = function ( renderer ) { + + _gl = renderer.context; + _renderer = renderer; + + vertices = new Float32Array( [ + - 0.5, - 0.5, 0, 0, + 0.5, - 0.5, 1, 0, + 0.5, 0.5, 1, 1, + - 0.5, 0.5, 0, 1 + ] ); + + faces = new Uint16Array( [ + 0, 1, 2, + 0, 2, 3 + ] ); + + vertexBuffer = _gl.createBuffer(); + elementBuffer = _gl.createBuffer(); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, vertexBuffer ); + _gl.bufferData( _gl.ARRAY_BUFFER, vertices, _gl.STATIC_DRAW ); + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faces, _gl.STATIC_DRAW ); + + program = createProgram(); + + attributes = { + position: _gl.getAttribLocation ( program, 'position' ), + uv: _gl.getAttribLocation ( program, 'uv' ) + }; + + uniforms = { + uvOffset: _gl.getUniformLocation( program, 'uvOffset' ), + uvScale: _gl.getUniformLocation( program, 'uvScale' ), + + rotation: _gl.getUniformLocation( program, 'rotation' ), + scale: _gl.getUniformLocation( program, 'scale' ), + + color: _gl.getUniformLocation( program, 'color' ), + map: _gl.getUniformLocation( program, 'map' ), + opacity: _gl.getUniformLocation( program, 'opacity' ), + + modelViewMatrix: _gl.getUniformLocation( program, 'modelViewMatrix' ), + projectionMatrix: _gl.getUniformLocation( program, 'projectionMatrix' ), + + fogType: _gl.getUniformLocation( program, 'fogType' ), + fogDensity: _gl.getUniformLocation( program, 'fogDensity' ), + fogNear: _gl.getUniformLocation( program, 'fogNear' ), + fogFar: _gl.getUniformLocation( program, 'fogFar' ), + fogColor: _gl.getUniformLocation( program, 'fogColor' ), + + alphaTest: _gl.getUniformLocation( program, 'alphaTest' ) + }; + + var canvas = document.createElement( 'canvas' ); + canvas.width = 8; + canvas.height = 8; + + var context = canvas.getContext( '2d' ); + context.fillStyle = '#ffffff'; + context.fillRect( 0, 0, canvas.width, canvas.height ); + + _texture = new THREE.Texture( canvas ); + _texture.needsUpdate = true; + + }; + + this.render = function ( scene, camera, viewportWidth, viewportHeight ) { + + var sprites = scene.__webglSprites, + nSprites = sprites.length; + + if ( ! nSprites ) return; + + // setup gl + + _gl.useProgram( program ); + + _gl.enableVertexAttribArray( attributes.position ); + _gl.enableVertexAttribArray( attributes.uv ); + + _gl.disable( _gl.CULL_FACE ); + _gl.enable( _gl.BLEND ); + + _gl.bindBuffer( _gl.ARRAY_BUFFER, vertexBuffer ); + _gl.vertexAttribPointer( attributes.position, 2, _gl.FLOAT, false, 2 * 8, 0 ); + _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 ); + + _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); + + _gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); + + _gl.activeTexture( _gl.TEXTURE0 ); + _gl.uniform1i( uniforms.map, 0 ); + + var oldFogType = 0; + var sceneFogType = 0; + var fog = scene.fog; + + if ( fog ) { + + _gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); + + if ( fog instanceof THREE.Fog ) { + + _gl.uniform1f( uniforms.fogNear, fog.near ); + _gl.uniform1f( uniforms.fogFar, fog.far ); + + _gl.uniform1i( uniforms.fogType, 1 ); + oldFogType = 1; + sceneFogType = 1; + + } else if ( fog instanceof THREE.FogExp2 ) { + + _gl.uniform1f( uniforms.fogDensity, fog.density ); + + _gl.uniform1i( uniforms.fogType, 2 ); + oldFogType = 2; + sceneFogType = 2; + + } + + } else { + + _gl.uniform1i( uniforms.fogType, 0 ); + oldFogType = 0; + sceneFogType = 0; + + } + + + // update positions and sort + + var i, sprite, material, fogType, scale = []; + + for( i = 0; i < nSprites; i ++ ) { + + sprite = sprites[ i ]; + material = sprite.material; + + if ( sprite.visible === false ) continue; + + sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); + sprite.z = - sprite._modelViewMatrix.elements[ 14 ]; + + } + + sprites.sort( painterSortStable ); + + // render all sprites + + for( i = 0; i < nSprites; i ++ ) { + + sprite = sprites[ i ]; + + if ( sprite.visible === false ) continue; + + material = sprite.material; + + _gl.uniform1f( uniforms.alphaTest, material.alphaTest ); + _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements ); + + scale[ 0 ] = sprite.scale.x; + scale[ 1 ] = sprite.scale.y; + + if ( scene.fog && material.fog ) { + + fogType = sceneFogType; + + } else { + + fogType = 0; + + } + + if ( oldFogType !== fogType ) { + + _gl.uniform1i( uniforms.fogType, fogType ); + oldFogType = fogType; + + } + + if ( material.map !== null ) { + + _gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y ); + _gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y ); + + } else { + + _gl.uniform2f( uniforms.uvOffset, 0, 0 ); + _gl.uniform2f( uniforms.uvScale, 1, 1 ); + + } + + _gl.uniform1f( uniforms.opacity, material.opacity ); + _gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); + + _gl.uniform1f( uniforms.rotation, material.rotation ); + _gl.uniform2fv( uniforms.scale, scale ); + + _renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + _renderer.setDepthTest( material.depthTest ); + _renderer.setDepthWrite( material.depthWrite ); + + if ( material.map && material.map.image && material.map.image.width ) { + + _renderer.setTexture( material.map, 0 ); + + } else { + + _renderer.setTexture( _texture, 0 ); + + } + + _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); + + } + + // restore gl + + _gl.enable( _gl.CULL_FACE ); + + }; + + function createProgram () { + + var program = _gl.createProgram(); + + var vertexShader = _gl.createShader( _gl.VERTEX_SHADER ); + var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER ); + + _gl.shaderSource( vertexShader, [ + + 'precision ' + _renderer.getPrecision() + ' float;', + + 'uniform mat4 modelViewMatrix;', + 'uniform mat4 projectionMatrix;', + 'uniform float rotation;', + 'uniform vec2 scale;', + 'uniform vec2 uvOffset;', + 'uniform vec2 uvScale;', + + 'attribute vec2 position;', + 'attribute vec2 uv;', + + 'varying vec2 vUV;', + + 'void main() {', + + 'vUV = uvOffset + uv * uvScale;', + + 'vec2 alignedPosition = position * scale;', + + 'vec2 rotatedPosition;', + 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;', + 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;', + + 'vec4 finalPosition;', + + 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );', + 'finalPosition.xy += rotatedPosition;', + 'finalPosition = projectionMatrix * finalPosition;', + + 'gl_Position = finalPosition;', + + '}' + + ].join( '\n' ) ); + + _gl.shaderSource( fragmentShader, [ + + 'precision ' + _renderer.getPrecision() + ' float;', + + 'uniform vec3 color;', + 'uniform sampler2D map;', + 'uniform float opacity;', + + 'uniform int fogType;', + 'uniform vec3 fogColor;', + 'uniform float fogDensity;', + 'uniform float fogNear;', + 'uniform float fogFar;', + 'uniform float alphaTest;', + + 'varying vec2 vUV;', + + 'void main() {', + + 'vec4 texture = texture2D( map, vUV );', + + 'if ( texture.a < alphaTest ) discard;', + + 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', + + 'if ( fogType > 0 ) {', + + 'float depth = gl_FragCoord.z / gl_FragCoord.w;', + 'float fogFactor = 0.0;', + + 'if ( fogType == 1 ) {', + + 'fogFactor = smoothstep( fogNear, fogFar, depth );', + + '} else {', + + 'const float LOG2 = 1.442695;', + 'float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );', + 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', + + '}', + + 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );', + + '}', + + '}' + + ].join( '\n' ) ); + + _gl.compileShader( vertexShader ); + _gl.compileShader( fragmentShader ); + + _gl.attachShader( program, vertexShader ); + _gl.attachShader( program, fragmentShader ); + + _gl.linkProgram( program ); + + return program; + + }; + + function painterSortStable ( a, b ) { + + if ( a.z !== b.z ) { + + return b.z - a.z; + + } else { + + return b.id - a.id; + + } + + }; + +}; + +/** + * @author alteredq / http://alteredqualia.com/ + */ + +THREE.DepthPassPlugin = function () { + + this.enabled = false; + this.renderTarget = null; + + var _gl, + _renderer, + _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, + + _frustum = new THREE.Frustum(), + _projScreenMatrix = new THREE.Matrix4(); + + this.init = function ( renderer ) { + + _gl = renderer.context; + _renderer = renderer; + + var depthShader = THREE.ShaderLib[ "depthRGBA" ]; + var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); + + _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); + _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); + _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); + _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); + + _depthMaterial._shadowPass = true; + _depthMaterialMorph._shadowPass = true; + _depthMaterialSkin._shadowPass = true; + _depthMaterialMorphSkin._shadowPass = true; + + }; + + this.render = function ( scene, camera ) { + + if ( ! this.enabled ) return; + + this.update( scene, camera ); + + }; + + this.update = function ( scene, camera ) { + + var i, il, j, jl, n, + + program, buffer, material, + webglObject, object, light, + renderList, + + fog = null; + + // set GL state for depth map + + _gl.clearColor( 1, 1, 1, 1 ); + _gl.disable( _gl.BLEND ); + + _renderer.setDepthTest( true ); + + // update scene + + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + + // update camera matrices and frustum + + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromMatrix( _projScreenMatrix ); + + // render depth map + + _renderer.setRenderTarget( this.renderTarget ); + _renderer.clear(); + + // set object matrices & frustum culling + + renderList = scene.__webglObjects; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + object = webglObject.object; + + webglObject.render = false; + + if ( object.visible ) { + + if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { + + object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + + webglObject.render = true; + + } + + } + + } + + // render regular objects + + var objectMaterial, useMorphing, useSkinning; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + + if ( webglObject.render ) { + + object = webglObject.object; + buffer = webglObject.buffer; + + // todo: create proper depth material for particles + + if ( object instanceof THREE.ParticleSystem && !object.customDepthMaterial ) continue; + + objectMaterial = getObjectMaterial( object ); + + if ( objectMaterial ) _renderer.setMaterialFaces( object.material ); + + useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; + useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; + + if ( object.customDepthMaterial ) { + + material = object.customDepthMaterial; + + } else if ( useSkinning ) { + + material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; + + } else if ( useMorphing ) { + + material = _depthMaterialMorph; + + } else { + + material = _depthMaterial; + + } + + if ( buffer instanceof THREE.BufferGeometry ) { + + _renderer.renderBufferDirect( camera, scene.__lights, fog, material, buffer, object ); + + } else { + + _renderer.renderBuffer( camera, scene.__lights, fog, material, buffer, object ); + + } + + } + + } + + // set matrices and render immediate objects + + renderList = scene.__webglObjectsImmediate; + + for ( j = 0, jl = renderList.length; j < jl; j ++ ) { + + webglObject = renderList[ j ]; + object = webglObject.object; + + if ( object.visible ) { + + object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + + _renderer.renderImmediateObject( camera, scene.__lights, fog, _depthMaterial, object ); + + } + + } + + // restore GL state + + var clearColor = _renderer.getClearColor(), + clearAlpha = _renderer.getClearAlpha(); + + _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); + _gl.enable( _gl.BLEND ); + + }; + + // For the moment just ignore objects that have multiple materials with different animation methods + // Only the first material will be taken into account for deciding which depth material to use + + function getObjectMaterial( object ) { + + return object.material instanceof THREE.MeshFaceMaterial + ? object.material.materials[ 0 ] + : object.material; + + }; + +}; + + +/** + * @author mikael emtinger / http://gomo.se/ + */ + +THREE.ShaderFlares = { + + 'lensFlareVertexTexture': { + + vertexShader: [ + + "uniform lowp int renderType;", + + "uniform vec3 screenPosition;", + "uniform vec2 scale;", + "uniform float rotation;", + + "uniform sampler2D occlusionMap;", + + "attribute vec2 position;", + "attribute vec2 uv;", + + "varying vec2 vUV;", + "varying float vVisibility;", + + "void main() {", + + "vUV = uv;", + + "vec2 pos = position;", + + "if( renderType == 2 ) {", + + "vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );", + "visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );", + + "vVisibility = visibility.r / 9.0;", + "vVisibility *= 1.0 - visibility.g / 9.0;", + "vVisibility *= visibility.b / 9.0;", + "vVisibility *= 1.0 - visibility.a / 9.0;", + + "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", + "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", + + "}", + + "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", + + "}" + + ].join( "\n" ), + + fragmentShader: [ + + "uniform lowp int renderType;", + + "uniform sampler2D map;", + "uniform float opacity;", + "uniform vec3 color;", + + "varying vec2 vUV;", + "varying float vVisibility;", + + "void main() {", + + // pink square + + "if( renderType == 0 ) {", + + "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", + + // restore + + "} else if( renderType == 1 ) {", + + "gl_FragColor = texture2D( map, vUV );", + + // flare + + "} else {", + + "vec4 texture = texture2D( map, vUV );", + "texture.a *= opacity * vVisibility;", + "gl_FragColor = texture;", + "gl_FragColor.rgb *= color;", + + "}", + + "}" + ].join( "\n" ) + + }, + + + 'lensFlare': { + + vertexShader: [ + + "uniform lowp int renderType;", + + "uniform vec3 screenPosition;", + "uniform vec2 scale;", + "uniform float rotation;", + + "attribute vec2 position;", + "attribute vec2 uv;", + + "varying vec2 vUV;", + + "void main() {", + + "vUV = uv;", + + "vec2 pos = position;", + + "if( renderType == 2 ) {", + + "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", + "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", + + "}", + + "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", + + "}" + + ].join( "\n" ), + + fragmentShader: [ + + "precision mediump float;", + + "uniform lowp int renderType;", + + "uniform sampler2D map;", + "uniform sampler2D occlusionMap;", + "uniform float opacity;", + "uniform vec3 color;", + + "varying vec2 vUV;", + + "void main() {", + + // pink square + + "if( renderType == 0 ) {", + + "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );", + + // restore + + "} else if( renderType == 1 ) {", + + "gl_FragColor = texture2D( map, vUV );", + + // flare + + "} else {", + + "float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;", + "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;", + "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;", + "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;", + "visibility = ( 1.0 - visibility / 4.0 );", + + "vec4 texture = texture2D( map, vUV );", + "texture.a *= opacity * visibility;", + "gl_FragColor = texture;", + "gl_FragColor.rgb *= color;", + + "}", + + "}" + + ].join( "\n" ) + + } + +}; + + +// Export the THREE object for **Node.js**, with +// backwards-compatibility for the old `require()` API. If we're in +// the browser, add `_` as a global object via a string identifier, +// for Closure Compiler "advanced" mode. +if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = THREE; + } + exports.THREE = THREE; +} else { + this['THREE'] = THREE; +} },{}],13:[function(require,module,exports){ // tween.js - http://github.com/sole/tween.js